blob: 25e8d522e2c2c13f2a9d176ac817b17101fd8dab [file] [log] [blame]
Radek Krejci9b4ca392015-04-10 08:31:27 +02001/**
2 * @file common.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief common libyang routines implementations
5 *
Michal Vasko4814fb02017-08-17 14:49:38 +02006 * Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
Radek Krejci9b4ca392015-04-10 08:31:27 +02007 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * 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
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci9b4ca392015-04-10 08:31:27 +020013 */
Radek Krejci7136a8e2015-08-17 13:37:30 +020014
Radek Krejci8b5924d2016-01-04 15:12:26 +010015#define _GNU_SOURCE
16
Michal Vasko9286afd2015-07-14 15:27:59 +020017#include <assert.h>
Michal Vasko9286afd2015-07-14 15:27:59 +020018#include <ctype.h>
Radek Krejci3d42f5e2016-02-08 12:22:27 +010019#include <errno.h>
20#include <limits.h>
Radek Krejci7d9f46a2016-01-29 13:53:18 +010021#include <pthread.h>
Radek Krejci3d42f5e2016-02-08 12:22:27 +010022#include <string.h>
23#include <stdlib.h>
24#include <sys/syscall.h>
Radek Krejcifd8c59b2016-02-05 15:40:20 +010025#include <sys/types.h>
Radek Krejcifd8c59b2016-02-05 15:40:20 +010026#include <unistd.h>
Radek Krejci9b4ca392015-04-10 08:31:27 +020027
28#include "common.h"
Michal Vasko921eb6b2017-10-13 10:01:39 +020029#include "parser.h"
Michal Vasko56d082c2016-10-25 14:00:42 +020030#include "xpath.h"
Michal Vaskof53187d2017-01-13 13:23:14 +010031#include "context.h"
Radek Krejci9b4ca392015-04-10 08:31:27 +020032
Michal Vasko53b7da02018-02-13 15:28:42 +010033THREAD_LOCAL enum int_log_opts log_opt;
34THREAD_LOCAL int8_t ly_errno_glob;
Radek Krejcifd8c59b2016-02-05 15:40:20 +010035
Michal Vasko4814fb02017-08-17 14:49:38 +020036API LY_ERR *
Michal Vasko53b7da02018-02-13 15:28:42 +010037ly_errno_glob_address(void)
Radek Krejci1d7f8d22016-02-08 14:15:51 +010038{
Michal Vasko53b7da02018-02-13 15:28:42 +010039 return (LY_ERR *)&ly_errno_glob;
Radek Krejci1d7f8d22016-02-08 14:15:51 +010040}
41
Michal Vasko53b7da02018-02-13 15:28:42 +010042API LY_VECODE
43ly_vecode(const struct ly_ctx *ctx)
Radek Krejci7d9f46a2016-01-29 13:53:18 +010044{
Michal Vasko53b7da02018-02-13 15:28:42 +010045 struct ly_err_item *i;
46
Michal Vasko10d6f2f2018-02-14 10:56:01 +010047 i = ly_err_first(ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +010048 if (i) {
Michal Vasko10d6f2f2018-02-14 10:56:01 +010049 return i->prev->vecode;
Michal Vasko53b7da02018-02-13 15:28:42 +010050 }
51
52 return 0;
Radek Krejci386714d2016-02-15 10:24:30 +010053}
54
Michal Vasko4814fb02017-08-17 14:49:38 +020055API const char *
Michal Vasko53b7da02018-02-13 15:28:42 +010056ly_errmsg(const struct ly_ctx *ctx)
Radek Krejci386714d2016-02-15 10:24:30 +010057{
Michal Vasko53b7da02018-02-13 15:28:42 +010058 struct ly_err_item *i;
59
Michal Vasko10d6f2f2018-02-14 10:56:01 +010060 i = ly_err_first(ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +010061 if (i) {
Michal Vasko10d6f2f2018-02-14 10:56:01 +010062 return i->prev->msg;
Michal Vasko53b7da02018-02-13 15:28:42 +010063 }
64
65 return NULL;
Michal Vasko4814fb02017-08-17 14:49:38 +020066}
Radek Krejci386714d2016-02-15 10:24:30 +010067
Michal Vasko4814fb02017-08-17 14:49:38 +020068API const char *
Michal Vasko53b7da02018-02-13 15:28:42 +010069ly_errpath(const struct ly_ctx *ctx)
Michal Vasko4814fb02017-08-17 14:49:38 +020070{
Michal Vasko53b7da02018-02-13 15:28:42 +010071 struct ly_err_item *i;
72
Michal Vasko10d6f2f2018-02-14 10:56:01 +010073 i = ly_err_first(ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +010074 if (i) {
Michal Vasko10d6f2f2018-02-14 10:56:01 +010075 return i->prev->path;
Michal Vasko53b7da02018-02-13 15:28:42 +010076 }
77
78 return NULL;
Michal Vasko4814fb02017-08-17 14:49:38 +020079}
Radek Krejci386714d2016-02-15 10:24:30 +010080
Michal Vasko4814fb02017-08-17 14:49:38 +020081API const char *
Michal Vasko53b7da02018-02-13 15:28:42 +010082ly_errapptag(const struct ly_ctx *ctx)
Michal Vasko4814fb02017-08-17 14:49:38 +020083{
Michal Vasko53b7da02018-02-13 15:28:42 +010084 struct ly_err_item *i;
85
Michal Vasko10d6f2f2018-02-14 10:56:01 +010086 i = ly_err_first(ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +010087 if (i) {
Michal Vasko10d6f2f2018-02-14 10:56:01 +010088 return i->prev->apptag;
Michal Vasko53b7da02018-02-13 15:28:42 +010089 }
90
91 return NULL;
92}
93
94API struct ly_err_item *
Michal Vasko10d6f2f2018-02-14 10:56:01 +010095ly_err_first(const struct ly_ctx *ctx)
Michal Vasko53b7da02018-02-13 15:28:42 +010096{
Michal Vaskoa93b4bb2018-02-14 13:59:52 +010097 if (!ctx) {
98 return NULL;
99 }
100
Michal Vasko10d6f2f2018-02-14 10:56:01 +0100101 return pthread_getspecific(ctx->errlist_key);
Radek Krejci7d9f46a2016-01-29 13:53:18 +0100102}
103
Radek Krejci2467a492016-10-24 15:16:59 +0200104void
Radek Krejcicf748252017-09-04 11:11:14 +0200105ly_err_free(void *ptr)
Radek Krejci2467a492016-10-24 15:16:59 +0200106{
107 struct ly_err_item *i, *next;
108
Radek Krejcicf748252017-09-04 11:11:14 +0200109 /* clean the error list */
110 for (i = (struct ly_err_item *)ptr; i; i = next) {
Radek Krejci2467a492016-10-24 15:16:59 +0200111 next = i->next;
112 free(i->msg);
113 free(i->path);
Michal Vasko53b7da02018-02-13 15:28:42 +0100114 free(i->apptag);
Radek Krejci2467a492016-10-24 15:16:59 +0200115 free(i);
116 }
Radek Krejcicf748252017-09-04 11:11:14 +0200117}
118
Michal Vasko53b7da02018-02-13 15:28:42 +0100119API void
120ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
Radek Krejcicf748252017-09-04 11:11:14 +0200121{
Michal Vasko53b7da02018-02-13 15:28:42 +0100122 struct ly_err_item *i, *first;
Radek Krejcicf748252017-09-04 11:11:14 +0200123
Michal Vasko10d6f2f2018-02-14 10:56:01 +0100124 first = ly_err_first(ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +0100125 if (first == eitem) {
126 eitem = NULL;
127 }
128 if (eitem) {
129 /* disconnect the error */
130 for (i = first; i && (i->next != eitem); i = i->next);
131 assert(i);
132 i->next = NULL;
133 first->prev = i;
134 /* free this err and newer */
135 ly_err_free(eitem);
136 /* update errno */
137 ly_errno = i->no;
138 } else {
139 /* free all err */
140 ly_err_free(first);
Radek Krejcicf748252017-09-04 11:11:14 +0200141 pthread_setspecific(ctx->errlist_key, NULL);
Michal Vasko53b7da02018-02-13 15:28:42 +0100142 /* also clean errno */
143 ly_errno = LY_SUCCESS;
Radek Krejcicf748252017-09-04 11:11:14 +0200144 }
Radek Krejcifbcbc092016-03-31 11:16:12 +0200145}
146
Radek Krejci15acd042016-02-05 17:09:39 +0100147#ifndef __USE_GNU
148
Radek Krejcia8d111f2017-05-31 13:57:37 +0200149char *
150get_current_dir_name(void)
Radek Krejci15acd042016-02-05 17:09:39 +0100151{
152 char tmp[PATH_MAX];
Radek Krejcia8d111f2017-05-31 13:57:37 +0200153 char *retval;
Radek Krejci15acd042016-02-05 17:09:39 +0100154
Radek Krejcia8d111f2017-05-31 13:57:37 +0200155 if (getcwd(tmp, sizeof(tmp))) {
156 retval = strdup(tmp);
Michal Vaskoec19dcf2018-02-14 16:29:14 +0100157 LY_CHECK_ERR_RETURN(!retval, LOGMEM(NULL), NULL);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200158 return retval;
159 }
Radek Krejci15acd042016-02-05 17:09:39 +0100160 return NULL;
161}
162
163#endif
164
Michal Vasko9016b562015-08-18 16:25:21 +0200165const char *
166strpbrk_backwards(const char *s, const char *accept, unsigned int s_len)
167{
168 const char *sc;
169
170 for (; *s != '\0' && s_len; --s, --s_len) {
171 for (sc = accept; *sc != '\0'; ++sc) {
Michal Vasko1433a0c2015-08-19 11:02:38 +0200172 if (*s == *sc) {
173 return s;
174 }
Michal Vasko9016b562015-08-18 16:25:21 +0200175 }
176 }
177 return s;
178}
179
Michal Vaskoa7d0be62015-06-16 10:43:49 +0200180char *
181strnchr(const char *s, int c, unsigned int len)
182{
183 for (; *s != (char)c; ++s, --len) {
184 if ((*s == '\0') || (!len)) {
185 return NULL;
186 }
187 }
188 return (char *)s;
189}
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200190
191const char *
Radek Krejci76512572015-08-04 09:47:08 +0200192strnodetype(LYS_NODE type)
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200193{
194 switch (type) {
Michal Vasko591e0b22015-08-13 13:53:43 +0200195 case LYS_UNKNOWN:
196 return NULL;
Radek Krejci76512572015-08-04 09:47:08 +0200197 case LYS_AUGMENT:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200198 return "augment";
Radek Krejci76512572015-08-04 09:47:08 +0200199 case LYS_CONTAINER:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200200 return "container";
Radek Krejci76512572015-08-04 09:47:08 +0200201 case LYS_CHOICE:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200202 return "choice";
Radek Krejci76512572015-08-04 09:47:08 +0200203 case LYS_LEAF:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200204 return "leaf";
Radek Krejci76512572015-08-04 09:47:08 +0200205 case LYS_LEAFLIST:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200206 return "leaf-list";
Radek Krejci76512572015-08-04 09:47:08 +0200207 case LYS_LIST:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200208 return "list";
Radek Krejci76512572015-08-04 09:47:08 +0200209 case LYS_ANYXML:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200210 return "anyxml";
Radek Krejci76512572015-08-04 09:47:08 +0200211 case LYS_GROUPING:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200212 return "grouping";
Radek Krejci76512572015-08-04 09:47:08 +0200213 case LYS_CASE:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200214 return "case";
Radek Krejci76512572015-08-04 09:47:08 +0200215 case LYS_INPUT:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200216 return "input";
Radek Krejci76512572015-08-04 09:47:08 +0200217 case LYS_OUTPUT:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200218 return "output";
Radek Krejci76512572015-08-04 09:47:08 +0200219 case LYS_NOTIF:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200220 return "notification";
Radek Krejci76512572015-08-04 09:47:08 +0200221 case LYS_RPC:
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200222 return "rpc";
Michal Vasko591e0b22015-08-13 13:53:43 +0200223 case LYS_USES:
224 return "uses";
Michal Vasko44fb6382016-06-29 11:12:27 +0200225 case LYS_ACTION:
226 return "action";
Radek Krejcibf2abff2016-08-23 15:51:52 +0200227 case LYS_ANYDATA:
228 return "anydata";
Radek Krejcif95b6292017-02-13 15:57:37 +0100229 case LYS_EXT:
230 return "extension instance";
Michal Vaskofbbcdb52015-07-03 14:26:21 +0200231 }
232
233 return NULL;
234}
Michal Vasko2e286202015-10-09 12:54:27 +0200235
Michal Vasko30646e62015-10-09 14:02:09 +0200236const char *
Michal Vaskoea733542016-02-05 13:14:23 +0100237transform_module_name2import_prefix(const struct lys_module *module, const char *module_name)
Michal Vasko2e286202015-10-09 12:54:27 +0200238{
Michal Vaskoea733542016-02-05 13:14:23 +0100239 uint16_t i;
240
Radek Krejcid1b3dba2017-01-13 11:31:12 +0100241 if (!module_name) {
242 return NULL;
243 }
244
Radek Krejcic4283442016-04-22 09:19:27 +0200245 if (!strcmp(lys_main_module(module)->name, module_name)) {
Michal Vaskoc271e972016-02-15 14:48:30 +0100246 /* the same for module and submodule */
Michal Vaskoea733542016-02-05 13:14:23 +0100247 return module->prefix;
248 }
249
250 for (i = 0; i < module->imp_size; ++i) {
251 if (!strcmp(module->imp[i].module->name, module_name)) {
252 return module->imp[i].prefix;
253 }
254 }
255
256 return NULL;
257}
258
Derek Pan57e0f1e2018-01-25 16:08:17 +0800259static int
260_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,
Michal Vaskoea733542016-02-05 13:14:23 +0100261 const char ***namespaces, uint32_t *ns_count)
262{
Derek Pan57e0f1e2018-01-25 16:08:17 +0800263 const char *cur_expr, *end, *prefix, *literal;
264 char *name;
265 size_t name_len;
Michal Vasko1b6ca962017-08-03 14:23:09 +0200266 const struct lys_module *mod = NULL, *prev_mod = NULL;
Michal Vasko56d082c2016-10-25 14:00:42 +0200267 uint32_t i, j;
268 struct lyxp_expr *exp;
Michal Vasko53b7da02018-02-13 15:28:42 +0100269 struct ly_ctx *ctx = module->ctx;
Michal Vasko2e286202015-10-09 12:54:27 +0200270
Michal Vasko30646e62015-10-09 14:02:09 +0200271 assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count)));
Michal Vasko2e286202015-10-09 12:54:27 +0200272
Michal Vasko53b7da02018-02-13 15:28:42 +0100273 exp = lyxp_parse_expr(ctx, expr);
Derek Pan57e0f1e2018-01-25 16:08:17 +0800274 LY_CHECK_RETURN(!exp, 1);
Michal Vasko2e286202015-10-09 12:54:27 +0200275
Michal Vasko56d082c2016-10-25 14:00:42 +0200276 for (i = 0; i < exp->used; ++i) {
277 cur_expr = &exp->expr[exp->expr_pos[i]];
Michal Vasko253035f2015-12-17 16:58:13 +0100278
Michal Vasko56d082c2016-10-25 14:00:42 +0200279 /* copy WS */
280 if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
Derek Pan57e0f1e2018-01-25 16:08:17 +0800281 strncpy(&(*out)[*out_used], end, cur_expr - end);
282 (*out_used) += cur_expr - end;
Michal Vasko56d082c2016-10-25 14:00:42 +0200283 }
284
Michal Vasko1b6ca962017-08-03 14:23:09 +0200285 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && ((end = strnchr(cur_expr, ':', exp->tok_len[i])) || inst_id)) {
Michal Vasko56d082c2016-10-25 14:00:42 +0200286 /* get the module */
Michal Vasko56d082c2016-10-25 14:00:42 +0200287 if (!schema) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200288 if (end) {
289 name_len = end - cur_expr;
290 name = strndup(cur_expr, name_len);
Michal Vaskod864d4c2017-12-06 09:59:29 +0100291 mod = ly_ctx_get_module(module->ctx, name, NULL, 0);
292 if (module->ctx->data_clb) {
293 if (!mod) {
294 mod = module->ctx->data_clb(module->ctx, name, NULL, 0, module->ctx->data_clb_data);
295 } else if (!mod->implemented) {
296 mod = module->ctx->data_clb(module->ctx, name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, module->ctx->data_clb_data);
297 }
298 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200299 free(name);
300 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100301 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
Michal Vasko1b6ca962017-08-03 14:23:09 +0200302 goto error;
303 }
304 prev_mod = mod;
305 } else {
306 mod = prev_mod;
307 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100308 LOGINT(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +0200309 goto error;
310 }
311 name_len = 0;
312 end = cur_expr;
Michal Vasko56d082c2016-10-25 14:00:42 +0200313 }
314 prefix = mod->prefix;
315 } else {
Radek Krejcid1507ca2017-08-09 13:09:41 +0200316 if (end) {
317 name_len = end - cur_expr;
318 } else {
319 name_len = strlen(cur_expr);
320 end = cur_expr;
321 }
Michal Vasko56d082c2016-10-25 14:00:42 +0200322 name = strndup(cur_expr, name_len);
323 prefix = transform_module_name2import_prefix(module, name);
324 free(name);
325 if (!prefix) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100326 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
Michal Vasko56d082c2016-10-25 14:00:42 +0200327 goto error;
328 }
329 }
330
331 /* remember the namespace definition (only if it's new) */
332 if (!schema && ns_count) {
333 for (j = 0; j < *ns_count; ++j) {
334 if (ly_strequal((*namespaces)[j], mod->ns, 1)) {
335 break;
336 }
337 }
338 if (j == *ns_count) {
339 ++(*ns_count);
340 *prefixes = ly_realloc(*prefixes, *ns_count * sizeof **prefixes);
Michal Vasko53b7da02018-02-13 15:28:42 +0100341 LY_CHECK_ERR_GOTO(!(*prefixes), LOGMEM(ctx), error);
Michal Vasko56d082c2016-10-25 14:00:42 +0200342 *namespaces = ly_realloc(*namespaces, *ns_count * sizeof **namespaces);
Michal Vasko53b7da02018-02-13 15:28:42 +0100343 LY_CHECK_ERR_GOTO(!(*namespaces), LOGMEM(ctx), error);
Michal Vasko56d082c2016-10-25 14:00:42 +0200344 (*prefixes)[*ns_count - 1] = mod->prefix;
345 (*namespaces)[*ns_count - 1] = mod->ns;
346 }
347 }
348
349 /* adjust out size (it can even decrease in some strange cases) */
Derek Pan57e0f1e2018-01-25 16:08:17 +0800350 *out_size += strlen(prefix) + 1 - name_len;
351 *out = ly_realloc(*out, *out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100352 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
Michal Vasko56d082c2016-10-25 14:00:42 +0200353
354 /* copy the model name */
Derek Pan57e0f1e2018-01-25 16:08:17 +0800355 strcpy(&(*out)[*out_used], prefix);
356 *out_used += strlen(prefix);
Michal Vasko56d082c2016-10-25 14:00:42 +0200357
Michal Vasko1b6ca962017-08-03 14:23:09 +0200358 if (!name_len) {
359 /* we are adding the prefix, so also ':' */
Derek Pan57e0f1e2018-01-25 16:08:17 +0800360 (*out)[*out_used] = ':';
361 ++(*out_used);
Michal Vasko1b6ca962017-08-03 14:23:09 +0200362 }
363
Michal Vasko56d082c2016-10-25 14:00:42 +0200364 /* copy the rest */
Derek Pan57e0f1e2018-01-25 16:08:17 +0800365 strncpy(&(*out)[*out_used], end, exp->tok_len[i] - name_len);
366 *out_used += exp->tok_len[i] - name_len;
Michal Vasko4b0727e2016-11-16 09:52:25 +0100367 } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
Derek Pan57e0f1e2018-01-25 16:08:17 +0800368 /* copy begin quote */
369 (*out)[*out_used] = cur_expr[0];
370 ++(*out_used);
371
372 /* skip quotes */
373 literal = lydict_insert(module->ctx, cur_expr + 1, exp->tok_len[i] - 2);
374
375 /* parse literals as subexpressions if possible, otherwise treat as a literal */
Derek Pan53e027f2018-02-06 14:16:57 +0800376 if (_transform_json2xml_subexp(module, literal, out, out_used, out_size, schema, inst_id, prefixes, namespaces, ns_count)) {
Michal Vasko91b2dcc2018-01-25 10:07:37 +0100377 strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2);
378 *out_used += exp->tok_len[i] - 2;
Michal Vasko4b0727e2016-11-16 09:52:25 +0100379 }
380
Derek Pan57e0f1e2018-01-25 16:08:17 +0800381 lydict_remove(module->ctx, literal);
Michal Vasko4b0727e2016-11-16 09:52:25 +0100382
Derek Pan57e0f1e2018-01-25 16:08:17 +0800383 /* copy end quote */
384 (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1];
385 ++(*out_used);
Michal Vasko56d082c2016-10-25 14:00:42 +0200386 } else {
Derek Pan57e0f1e2018-01-25 16:08:17 +0800387 strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
388 *out_used += exp->tok_len[i];
Michal Vasko56d082c2016-10-25 14:00:42 +0200389 }
390 }
Michal Vasko56d082c2016-10-25 14:00:42 +0200391
Michal Vasko89afc112017-03-16 13:57:28 +0100392 lyxp_expr_free(exp);
Derek Pan57e0f1e2018-01-25 16:08:17 +0800393 return 0;
Michal Vasko56d082c2016-10-25 14:00:42 +0200394
395error:
Michal Vaskoea733542016-02-05 13:14:23 +0100396 if (!schema && ns_count) {
397 free(*prefixes);
398 free(*namespaces);
399 }
Michal Vasko89afc112017-03-16 13:57:28 +0100400 lyxp_expr_free(exp);
Derek Pan57e0f1e2018-01-25 16:08:17 +0800401 return 1;
402}
403
404static const char *
405_transform_json2xml(const struct lys_module *module, const char *expr, int schema, int inst_id, const char ***prefixes,
406 const char ***namespaces, uint32_t *ns_count)
407{
408 char *out;
409 size_t out_size, out_used;
410 int ret;
411
412 assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count)));
413
Derek Pan24189d02018-01-30 15:38:24 +0800414 if (ns_count) {
415 *ns_count = 0;
416 *prefixes = NULL;
417 *namespaces = NULL;
418 }
419
Derek Pan57e0f1e2018-01-25 16:08:17 +0800420 if (!expr[0]) {
421 /* empty value */
422 return lydict_insert(module->ctx, expr, 0);
423 }
424
425 out_size = strlen(expr) + 1;
426 out = malloc(out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100427 LY_CHECK_ERR_RETURN(!out, LOGMEM(module->ctx), NULL);
Derek Pan57e0f1e2018-01-25 16:08:17 +0800428 out_used = 0;
429
430 ret = _transform_json2xml_subexp(module, expr, &out, &out_used, &out_size, schema, inst_id, prefixes, namespaces, ns_count);
431 if (!ret) {
432 out[out_used] = '\0';
433 return lydict_insert_zc(module->ctx, out);
434 }
435
436 free(out);
Michal Vasko2e286202015-10-09 12:54:27 +0200437 return NULL;
438}
439
440const char *
Michal Vasko1b6ca962017-08-03 14:23:09 +0200441transform_json2xml(const struct lys_module *module, const char *expr, int inst_id, const char ***prefixes,
442 const char ***namespaces, uint32_t *ns_count)
Michal Vaskoea733542016-02-05 13:14:23 +0100443{
Michal Vasko1b6ca962017-08-03 14:23:09 +0200444 return _transform_json2xml(module, expr, 0, inst_id, prefixes, namespaces, ns_count);
Michal Vaskoea733542016-02-05 13:14:23 +0100445}
446
447const char *
448transform_json2schema(const struct lys_module *module, const char *expr)
449{
Michal Vasko1b6ca962017-08-03 14:23:09 +0200450 return _transform_json2xml(module, expr, 1, 0, NULL, NULL, NULL);
Michal Vaskoea733542016-02-05 13:14:23 +0100451}
452
Michal Vasko6be951e2018-01-23 13:20:51 +0100453static int
454transform_xml2json_subexp(struct ly_ctx *ctx, const char *expr, char **out, size_t *out_used, size_t *out_size,
Michal Vasko53b7da02018-02-13 15:28:42 +0100455 struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb)
Michal Vasko2e286202015-10-09 12:54:27 +0200456{
Michal Vasko6be951e2018-01-23 13:20:51 +0100457 const char *end, *cur_expr, *literal;
458 char *prefix;
Michal Vasko56d082c2016-10-25 14:00:42 +0200459 uint16_t i;
Michal Vasko53b7da02018-02-13 15:28:42 +0100460 enum int_log_opts prev_ilo;
Michal Vasko6be951e2018-01-23 13:20:51 +0100461 size_t pref_len;
Michal Vasko1b6ca962017-08-03 14:23:09 +0200462 const struct lys_module *mod, *prev_mod = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100463 const struct lyxml_ns *ns;
Michal Vasko56d082c2016-10-25 14:00:42 +0200464 struct lyxp_expr *exp;
Michal Vasko2e286202015-10-09 12:54:27 +0200465
Michal Vasko53b7da02018-02-13 15:28:42 +0100466 exp = lyxp_parse_expr(ctx, expr);
Michal Vasko56d082c2016-10-25 14:00:42 +0200467 if (!exp) {
Michal Vasko6be951e2018-01-23 13:20:51 +0100468 return 1;
Michal Vasko2e286202015-10-09 12:54:27 +0200469 }
470
Michal Vasko56d082c2016-10-25 14:00:42 +0200471 for (i = 0; i < exp->used; ++i) {
472 cur_expr = &exp->expr[exp->expr_pos[i]];
473
474 /* copy WS */
475 if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
Michal Vasko6be951e2018-01-23 13:20:51 +0100476 strncpy(&(*out)[*out_used], end, cur_expr - end);
477 (*out_used) += cur_expr - end;
Michal Vasko56d082c2016-10-25 14:00:42 +0200478 }
479
480 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
481 /* get the module */
482 pref_len = end - cur_expr;
483 prefix = strndup(cur_expr, pref_len);
484 if (!prefix) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100485 LOGMEM(ctx);
Michal Vasko56d082c2016-10-25 14:00:42 +0200486 goto error;
487 }
488 ns = lyxml_get_ns(xml, prefix);
489 free(prefix);
490 if (!ns) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100491 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prefix");
492 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "XML namespace with prefix \"%.*s\" not defined.", pref_len, cur_expr);
Michal Vasko56d082c2016-10-25 14:00:42 +0200493 goto error;
494 }
Michal Vaskod864d4c2017-12-06 09:59:29 +0100495 mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 0);
Michal Vaskof53187d2017-01-13 13:23:14 +0100496 if (use_ctx_data_clb && ctx->data_clb) {
497 if (!mod) {
498 mod = ctx->data_clb(ctx, NULL, ns->value, 0, ctx->data_clb_data);
499 } else if (!mod->implemented) {
500 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
501 }
502 }
Michal Vasko56d082c2016-10-25 14:00:42 +0200503 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100504 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "module namespace");
505 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Module with the namespace \"%s\" could not be found.", ns->value);
Michal Vasko56d082c2016-10-25 14:00:42 +0200506 goto error;
507 }
508
Michal Vasko1b6ca962017-08-03 14:23:09 +0200509 if (!inst_id || (mod != prev_mod)) {
510 /* adjust out size (it can even decrease in some strange cases) */
Michal Vasko6be951e2018-01-23 13:20:51 +0100511 *out_size += strlen(mod->name) - pref_len;
512 *out = ly_realloc(*out, *out_size);
513 if (!(*out)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100514 LOGMEM(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +0200515 goto error;
Michal Vasko56d082c2016-10-25 14:00:42 +0200516 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200517
518 /* copy the model name */
Michal Vasko6be951e2018-01-23 13:20:51 +0100519 strcpy(&(*out)[*out_used], mod->name);
520 *out_used += strlen(mod->name);
Michal Vasko1b6ca962017-08-03 14:23:09 +0200521 } else {
522 /* skip ':' */
523 ++end;
524 ++pref_len;
Michal Vasko56d082c2016-10-25 14:00:42 +0200525 }
526
Michal Vasko1b6ca962017-08-03 14:23:09 +0200527 /* remember previous model name */
528 prev_mod = mod;
Michal Vasko56d082c2016-10-25 14:00:42 +0200529
Michal Vasko56d082c2016-10-25 14:00:42 +0200530 /* copy the rest */
Michal Vasko6be951e2018-01-23 13:20:51 +0100531 strncpy(&(*out)[*out_used], end, exp->tok_len[i] - pref_len);
532 *out_used += exp->tok_len[i] - pref_len;
Michal Vasko1b6ca962017-08-03 14:23:09 +0200533 } else if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && inst_id) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100534 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prefix");
535 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Node name is missing module prefix.");
Michal Vasko1b6ca962017-08-03 14:23:09 +0200536 goto error;
Michal Vasko4b0727e2016-11-16 09:52:25 +0100537 } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
Michal Vasko6be951e2018-01-23 13:20:51 +0100538 /* copy begin quote */
539 (*out)[*out_used] = cur_expr[0];
540 ++(*out_used);
541
542 /* skip quotes */
543 literal = lydict_insert(ctx, cur_expr + 1, exp->tok_len[i] - 2);
544
Michal Vasko53b7da02018-02-13 15:28:42 +0100545 /* parse literals as subexpressions if possible, otherwise treat as a literal, do not log */
546 prev_ilo = log_opt;
547 log_opt = ILO_IGNORE;
548 if (transform_xml2json_subexp(ctx, literal, out, out_used, out_size, xml, inst_id, use_ctx_data_clb)) {
Michal Vasko91b2dcc2018-01-25 10:07:37 +0100549 strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2);
550 *out_used += exp->tok_len[i] - 2;
Michal Vasko4b0727e2016-11-16 09:52:25 +0100551 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100552 log_opt = prev_ilo;
Michal Vasko4b0727e2016-11-16 09:52:25 +0100553
Michal Vasko6be951e2018-01-23 13:20:51 +0100554 lydict_remove(ctx, literal);
Michal Vasko4b0727e2016-11-16 09:52:25 +0100555
Michal Vasko6be951e2018-01-23 13:20:51 +0100556 /* copy end quote */
557 (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1];
558 ++(*out_used);
Michal Vasko56d082c2016-10-25 14:00:42 +0200559 } else {
Michal Vasko6be951e2018-01-23 13:20:51 +0100560 strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
561 *out_used += exp->tok_len[i];
Michal Vasko56d082c2016-10-25 14:00:42 +0200562 }
563 }
Michal Vasko56d082c2016-10-25 14:00:42 +0200564
Michal Vasko89afc112017-03-16 13:57:28 +0100565 lyxp_expr_free(exp);
Michal Vasko6be951e2018-01-23 13:20:51 +0100566 return 0;
Michal Vasko56d082c2016-10-25 14:00:42 +0200567
568error:
Michal Vasko89afc112017-03-16 13:57:28 +0100569 lyxp_expr_free(exp);
Michal Vasko6be951e2018-01-23 13:20:51 +0100570 return 1;
571}
572
573const char *
Michal Vasko53b7da02018-02-13 15:28:42 +0100574transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb)
Michal Vasko6be951e2018-01-23 13:20:51 +0100575{
576 char *out;
577 size_t out_size, out_used;
578 int ret;
579
580 out_size = strlen(expr) + 1;
581 out = malloc(out_size);
582 if (!out) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100583 LOGMEM(ctx);
Michal Vasko6be951e2018-01-23 13:20:51 +0100584 return NULL;
585 }
586 out_used = 0;
587
Michal Vasko53b7da02018-02-13 15:28:42 +0100588 ret = transform_xml2json_subexp(ctx, expr, &out, &out_used, &out_size, xml, inst_id, use_ctx_data_clb);
Michal Vasko6be951e2018-01-23 13:20:51 +0100589 if (!ret) {
590 out[out_used] = '\0';
591 return lydict_insert_zc(ctx, out);
592 }
593
594 free(out);
Michal Vasko2e286202015-10-09 12:54:27 +0200595 return NULL;
596}
Michal Vaskofba15262015-10-21 12:10:28 +0200597
Michal Vasko065c5652018-03-08 15:35:21 +0100598API char *
599ly_path_xml2json(struct ly_ctx *ctx, const char *xml_path, struct lyxml_elem *xml)
600{
601 const char *json_path;
602 char *ret = NULL;
603
604 if (!ctx || !xml_path || !xml) {
605 LOGARG;
606 return NULL;
607 }
608
609 json_path = transform_xml2json(ctx, xml_path, xml, 0, 1);
610 if (json_path) {
611 ret = strdup(json_path);
612 lydict_remove(ctx, json_path);
613 }
614
615 return ret;
616}
617
Michal Vaskofba15262015-10-21 12:10:28 +0200618const char *
Radek Krejci48464ed2016-03-17 15:44:09 +0100619transform_schema2json(const struct lys_module *module, const char *expr)
Michal Vaskofba15262015-10-21 12:10:28 +0200620{
Michal Vasko4b0727e2016-11-16 09:52:25 +0100621 const char *end, *cur_expr, *ptr;
Michal Vasko56d082c2016-10-25 14:00:42 +0200622 char *out;
623 uint16_t i;
624 size_t out_size, out_used, pref_len;
625 const struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +0100626 struct ly_ctx *ctx = module->ctx;
Radek Krejci5717e432016-11-04 10:33:04 +0100627 struct lyxp_expr *exp = NULL;
Michal Vasko56d082c2016-10-25 14:00:42 +0200628
629 out_size = strlen(expr) + 1;
630 out = malloc(out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100631 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
Michal Vasko56d082c2016-10-25 14:00:42 +0200632 out_used = 0;
633
Michal Vasko53b7da02018-02-13 15:28:42 +0100634 exp = lyxp_parse_expr(ctx, expr);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200635 LY_CHECK_ERR_GOTO(!exp, , error);
Michal Vasko56d082c2016-10-25 14:00:42 +0200636
637 for (i = 0; i < exp->used; ++i) {
638 cur_expr = &exp->expr[exp->expr_pos[i]];
639
640 /* copy WS */
641 if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
642 strncpy(&out[out_used], end, cur_expr - end);
643 out_used += cur_expr - end;
644 }
645
646 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
647 /* get the module */
648 pref_len = end - cur_expr;
Michal Vasko921eb6b2017-10-13 10:01:39 +0200649 mod = lyp_get_module(module, cur_expr, pref_len, NULL, 0, 0);
Michal Vasko56d082c2016-10-25 14:00:42 +0200650 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100651 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, pref_len, cur_expr);
Radek Krejci5717e432016-11-04 10:33:04 +0100652 goto error;
Michal Vasko56d082c2016-10-25 14:00:42 +0200653 }
654
655 /* adjust out size (it can even decrease in some strange cases) */
656 out_size += strlen(mod->name) - pref_len;
657 out = ly_realloc(out, out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100658 LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error);
Michal Vasko56d082c2016-10-25 14:00:42 +0200659
660 /* copy the model name */
661 strcpy(&out[out_used], mod->name);
662 out_used += strlen(mod->name);
663
Michal Vasko56d082c2016-10-25 14:00:42 +0200664 /* copy the rest */
Michal Vasko4b0727e2016-11-16 09:52:25 +0100665 strncpy(&out[out_used], end, exp->tok_len[i] - pref_len);
666 out_used += exp->tok_len[i] - pref_len;
667 } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
668 ptr = end;
669 while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
670 --ptr;
671 }
672
673 /* get the module */
674 pref_len = end - ptr;
Michal Vasko921eb6b2017-10-13 10:01:39 +0200675 mod = lyp_get_module(module, ptr, pref_len, NULL, 0, 0);
Michal Vasko4b0727e2016-11-16 09:52:25 +0100676 if (mod) {
677 /* adjust out size (it can even decrease in some strange cases) */
678 out_size += strlen(mod->name) - pref_len;
679 out = ly_realloc(out, out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100680 LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error);
Michal Vasko4b0727e2016-11-16 09:52:25 +0100681
682 /* copy any beginning */
683 strncpy(&out[out_used], cur_expr, ptr - cur_expr);
684 out_used += ptr - cur_expr;
685
686 /* copy the model name */
687 strcpy(&out[out_used], mod->name);
688 out_used += strlen(mod->name);
689
690 /* copy the rest */
691 strncpy(&out[out_used], end, (exp->tok_len[i] - pref_len) - (ptr - cur_expr));
692 out_used += (exp->tok_len[i] - pref_len) - (ptr - cur_expr);
693 } else {
694 strncpy(&out[out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
695 out_used += exp->tok_len[i];
696 }
Michal Vasko56d082c2016-10-25 14:00:42 +0200697 } else {
698 strncpy(&out[out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
699 out_used += exp->tok_len[i];
700 }
701 }
702 out[out_used] = '\0';
703
Michal Vasko89afc112017-03-16 13:57:28 +0100704 lyxp_expr_free(exp);
Michal Vasko56d082c2016-10-25 14:00:42 +0200705 return lydict_insert_zc(module->ctx, out);
706
707error:
708 free(out);
Michal Vasko89afc112017-03-16 13:57:28 +0100709 lyxp_expr_free(exp);
Michal Vasko56d082c2016-10-25 14:00:42 +0200710 return NULL;
711}
712
713const char *
714transform_iffeat_schema2json(const struct lys_module *module, const char *expr)
715{
Michal Vaskofba15262015-10-21 12:10:28 +0200716 const char *in, *id;
717 char *out, *col;
718 size_t out_size, out_used, id_len, rc;
Michal Vasko1e62a092015-12-01 12:27:20 +0100719 const struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +0100720 struct ly_ctx *ctx = module->ctx;
Michal Vaskofba15262015-10-21 12:10:28 +0200721
722 in = expr;
Michal Vasko4b0727e2016-11-16 09:52:25 +0100723 out_size = strlen(in) + 1;
Michal Vaskofba15262015-10-21 12:10:28 +0200724 out = malloc(out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100725 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
Michal Vaskofba15262015-10-21 12:10:28 +0200726 out_used = 0;
727
728 while (1) {
729 col = strchr(in, ':');
730 /* we're finished, copy the remaining part */
731 if (!col) {
732 strcpy(&out[out_used], in);
Michal Vasko4b0727e2016-11-16 09:52:25 +0100733 out_used += strlen(in) + 1;
Michal Vaskofba15262015-10-21 12:10:28 +0200734 assert(out_size == out_used);
Michal Vasko53b7da02018-02-13 15:28:42 +0100735 return lydict_insert_zc(ctx, out);
Michal Vaskofba15262015-10-21 12:10:28 +0200736 }
Michal Vasko4b0727e2016-11-16 09:52:25 +0100737 id = strpbrk_backwards(col - 1, "/ [\'\"", (col - in) - 1);
Michal Vasko56d082c2016-10-25 14:00:42 +0200738 if ((id[0] == '/') || (id[0] == ' ') || (id[0] == '[') || (id[0] == '\'') || (id[0] == '\"')) {
Michal Vaskofba15262015-10-21 12:10:28 +0200739 ++id;
740 }
Michal Vasko4b0727e2016-11-16 09:52:25 +0100741 id_len = col - id;
Michal Vaskofba15262015-10-21 12:10:28 +0200742 rc = parse_identifier(id);
743 if (rc < id_len) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100744 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, id[rc], &id[rc]);
Michal Vaskofba15262015-10-21 12:10:28 +0200745 free(out);
746 return NULL;
747 }
748
749 /* get the module */
Michal Vasko921eb6b2017-10-13 10:01:39 +0200750 mod = lyp_get_module(module, id, id_len, NULL, 0, 0);
Michal Vaskofba15262015-10-21 12:10:28 +0200751 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100752 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, id_len, id);
Michal Vaskofba15262015-10-21 12:10:28 +0200753 free(out);
754 return NULL;
755 }
756
757 /* adjust out size (it can even decrease in some strange cases) */
Michal Vasko4b0727e2016-11-16 09:52:25 +0100758 out_size += strlen(mod->name) - id_len;
Michal Vasko253035f2015-12-17 16:58:13 +0100759 out = ly_realloc(out, out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100760 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
Michal Vaskofba15262015-10-21 12:10:28 +0200761
762 /* copy the data before prefix */
Michal Vasko4b0727e2016-11-16 09:52:25 +0100763 strncpy(&out[out_used], in, id - in);
764 out_used += id - in;
Michal Vaskofba15262015-10-21 12:10:28 +0200765
766 /* copy the model name */
767 strcpy(&out[out_used], mod->name);
768 out_used += strlen(mod->name);
769
770 /* copy ':' */
771 out[out_used] = ':';
772 ++out_used;
773
774 /* finally adjust in pointer for next round */
Michal Vasko4b0727e2016-11-16 09:52:25 +0100775 in = col + 1;
Michal Vaskofba15262015-10-21 12:10:28 +0200776 }
777
778 /* unreachable */
Michal Vasko53b7da02018-02-13 15:28:42 +0100779 LOGINT(ctx);
Michal Vaskofba15262015-10-21 12:10:28 +0200780 return NULL;
781}
Michal Vasko253035f2015-12-17 16:58:13 +0100782
Michal Vasko50576712017-07-28 12:28:33 +0200783static int
784transform_json2xpath_subexpr(const struct lys_module *cur_module, const struct lys_module *prev_mod, struct lyxp_expr *exp,
785 uint32_t *i, enum lyxp_token end_token, char **out, size_t *out_used, size_t *out_size)
786{
787 const char *cur_expr, *end, *ptr;
788 size_t name_len;
789 char *name;
790 const struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +0100791 struct ly_ctx *ctx = cur_module->ctx;
Michal Vasko50576712017-07-28 12:28:33 +0200792
793 while (*i < exp->used) {
794 if (exp->tokens[*i] == end_token) {
795 return 0;
796 }
797
798 cur_expr = &exp->expr[exp->expr_pos[*i]];
799
800 /* copy WS */
801 if (*i && ((end = exp->expr + exp->expr_pos[*i - 1] + exp->tok_len[*i - 1]) != cur_expr)) {
802 strncpy(*out + *out_used, end, cur_expr - end);
803 *out_used += cur_expr - end;
804 }
805
806 if (exp->tokens[*i] == LYXP_TOKEN_BRACK1) {
807 /* copy "[" */
808 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
809 *out_used += exp->tok_len[*i];
810 ++(*i);
811
812 /* call recursively because we need to remember current prev_mod for after the predicate */
813 if (transform_json2xpath_subexpr(cur_module, prev_mod, exp, i, LYXP_TOKEN_BRACK2, out, out_used, out_size)) {
814 return -1;
815 }
816
Michal Vaskoe59c1092017-12-12 09:49:21 +0100817 if (*i >= exp->used) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100818 LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL);
Michal Vaskoe59c1092017-12-12 09:49:21 +0100819 return -1;
820 }
821
Michal Vasko50576712017-07-28 12:28:33 +0200822 /* copy "]" */
823 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
824 *out_used += exp->tok_len[*i];
825 } else if (exp->tokens[*i] == LYXP_TOKEN_NAMETEST) {
826 if ((end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
827 /* there is a prefix, get the module */
828 name_len = end - cur_expr;
829 name = strndup(cur_expr, name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +0100830 prev_mod = ly_ctx_get_module(ctx, name, NULL, 1);
Radek Krejcia62a9d12017-08-09 12:37:51 +0200831 free(name);
Michal Vasko50576712017-07-28 12:28:33 +0200832 if (!prev_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100833 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len ? name_len : exp->tok_len[*i], cur_expr);
Michal Vasko50576712017-07-28 12:28:33 +0200834 return -1;
835 }
Michal Vasko50576712017-07-28 12:28:33 +0200836 /* skip ":" */
837 ++end;
838 ++name_len;
839 } else {
840 end = cur_expr;
841 name_len = 0;
842 }
843
Michal Vasko2a216f22018-05-14 10:15:27 +0200844 /* do we print the module name? (always for "*" if there was any, it's an exception) */
845 if ((prev_mod != cur_module) || (name_len && (end[0] == '*'))) {
Michal Vasko50576712017-07-28 12:28:33 +0200846 /* adjust out size (it can even decrease in some strange cases) */
847 *out_size += (strlen(prev_mod->name) - name_len) + 1;
848 *out = ly_realloc(*out, *out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100849 LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +0200850
851 /* copy the model name */
852 strcpy(*out + *out_used, prev_mod->name);
853 *out_used += strlen(prev_mod->name);
854
855 /* print ":" */
856 (*out)[*out_used] = ':';
857 ++(*out_used);
858 }
859
860 /* copy the rest */
861 strncpy(*out + *out_used, end, exp->tok_len[*i] - name_len);
862 *out_used += exp->tok_len[*i] - name_len;
863 } else if ((exp->tokens[*i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
864 ptr = end;
865 while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
866 --ptr;
867 }
868
869 /* get the module, but it may actually not be a module name */
870 name_len = end - ptr;
871 name = strndup(ptr, name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +0100872 mod = ly_ctx_get_module(ctx, name, NULL, 1);
Michal Vasko50576712017-07-28 12:28:33 +0200873 free(name);
874
875 if (mod && (mod != cur_module)) {
876 /* adjust out size (it can even decrease in some strange cases) */
877 *out_size += strlen(mod->name) - name_len;
878 *out = ly_realloc(*out, *out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100879 LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +0200880
881 /* copy any beginning */
882 strncpy(*out + *out_used, cur_expr, ptr - cur_expr);
883 *out_used += ptr - cur_expr;
884
885 /* copy the model name */
886 strcpy(*out + *out_used, mod->name);
887 *out_used += strlen(mod->name);
888
889 /* copy the rest */
890 strncpy(*out + *out_used, end, (exp->tok_len[*i] - name_len) - (ptr - cur_expr));
891 *out_used += (exp->tok_len[*i] - name_len) - (ptr - cur_expr);
892 } else {
893 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
894 *out_used += exp->tok_len[*i];
895 }
896 } else {
897 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
898 *out_used += exp->tok_len[*i];
899 }
900
901 ++(*i);
902 }
903
904 return 0;
905}
906
907char *
908transform_json2xpath(const struct lys_module *cur_module, const char *expr)
909{
910 char *out;
911 size_t out_size, out_used;
912 uint32_t i;
913 struct lyxp_expr *exp;
914
915 assert(cur_module && expr);
916
917 out_size = strlen(expr) + 1;
918 out = malloc(out_size);
Michal Vasko53b7da02018-02-13 15:28:42 +0100919 LY_CHECK_ERR_RETURN(!out, LOGMEM(cur_module->ctx), NULL);
Michal Vasko50576712017-07-28 12:28:33 +0200920 out_used = 0;
921
Michal Vasko53b7da02018-02-13 15:28:42 +0100922 exp = lyxp_parse_expr(cur_module->ctx, expr);
Michal Vasko50576712017-07-28 12:28:33 +0200923 LY_CHECK_ERR_RETURN(!exp, free(out), NULL);
924
925 i = 0;
926 if (transform_json2xpath_subexpr(cur_module, cur_module, exp, &i, LYXP_TOKEN_NONE, &out, &out_used, &out_size)) {
927 goto error;
928 }
929 out[out_used] = '\0';
930
931 lyxp_expr_free(exp);
932 return out;
933
934error:
935 free(out);
936 lyxp_expr_free(exp);
937 return NULL;
938}
939
Michal Vaskoee10f8c2017-10-25 14:47:05 +0200940static int
Michal Vasko53b7da02018-02-13 15:28:42 +0100941ly_path_data2schema_copy_token(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t cur_exp, char **out, uint16_t *out_used)
Michal Vasko25095332017-11-14 09:31:24 +0100942{
943 uint16_t len;
944
945 for (len = exp->tok_len[cur_exp]; isspace(exp->expr[exp->expr_pos[cur_exp] + len]); ++len);
946 *out = ly_realloc(*out, *out_used + len);
Michal Vasko53b7da02018-02-13 15:28:42 +0100947 LY_CHECK_ERR_RETURN(!(*out), LOGMEM(ctx), -1);
Michal Vasko25095332017-11-14 09:31:24 +0100948 sprintf(*out + *out_used - 1, "%.*s", len, exp->expr + exp->expr_pos[cur_exp]);
949 *out_used += len;
950
951 return 0;
952}
953
954static int
Michal Vaskoee10f8c2017-10-25 14:47:05 +0200955ly_path_data2schema_subexp(const struct ly_ctx *ctx, const struct lys_node *orig_parent, const struct lys_module *cur_mod,
956 struct lyxp_expr *exp, uint16_t *cur_exp, char **out, uint16_t *out_used)
Michal Vasko40702732017-10-25 11:43:23 +0200957{
Michal Vaskoee10f8c2017-10-25 14:47:05 +0200958 uint16_t j, k, len, slash;
959 char *str = NULL, *col;
960 const struct lys_node *node, *node2, *parent;
961 enum lyxp_token end_token = 0;
Michal Vasko25095332017-11-14 09:31:24 +0100962 int first, path_lost;
Michal Vasko40702732017-10-25 11:43:23 +0200963
Michal Vasko25095332017-11-14 09:31:24 +0100964 switch (exp->tokens[*cur_exp]) {
965 case LYXP_TOKEN_BRACK1:
Michal Vaskoee10f8c2017-10-25 14:47:05 +0200966 end_token = LYXP_TOKEN_BRACK2;
967
Michal Vasko53b7da02018-02-13 15:28:42 +0100968 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
Michal Vasko25095332017-11-14 09:31:24 +0100969 goto error;
970 }
Michal Vaskoee10f8c2017-10-25 14:47:05 +0200971 ++(*cur_exp);
Michal Vasko25095332017-11-14 09:31:24 +0100972 first = 0;
973 break;
974 case LYXP_TOKEN_PAR1:
975 end_token = LYXP_TOKEN_PAR2;
976
Michal Vasko53b7da02018-02-13 15:28:42 +0100977 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
Michal Vasko25095332017-11-14 09:31:24 +0100978 goto error;
979 }
980 ++(*cur_exp);
981 first = 0;
982 break;
PavolVicanb28bbff2018-02-21 00:44:02 +0100983 case LYXP_TOKEN_OPERATOR_PATH:
984 first = (orig_parent) ? 0 : 1;
985 break;
Michal Vasko25095332017-11-14 09:31:24 +0100986 default:
987 first = 1;
988 break;
Michal Vasko40702732017-10-25 11:43:23 +0200989 }
990
Michal Vasko25095332017-11-14 09:31:24 +0100991 path_lost = 0;
Michal Vaskoee10f8c2017-10-25 14:47:05 +0200992 parent = orig_parent;
993 while (*cur_exp < exp->used) {
994 switch (exp->tokens[*cur_exp]) {
Michal Vasko40702732017-10-25 11:43:23 +0200995 case LYXP_TOKEN_DOT:
Michal Vasko25095332017-11-14 09:31:24 +0100996 case LYXP_TOKEN_DDOT:
Michal Vasko40702732017-10-25 11:43:23 +0200997 case LYXP_TOKEN_NAMETEST:
Michal Vasko25095332017-11-14 09:31:24 +0100998 if (path_lost) {
999 /* we do not know anything anymore, just copy it */
Michal Vasko53b7da02018-02-13 15:28:42 +01001000 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
Michal Vasko25095332017-11-14 09:31:24 +01001001 goto error;
1002 }
1003 break;
1004 }
1005
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001006 str = strndup(exp->expr + exp->expr_pos[*cur_exp], exp->tok_len[*cur_exp]);
Michal Vasko53b7da02018-02-13 15:28:42 +01001007 LY_CHECK_ERR_GOTO(!str, LOGMEM(ctx), error);
Michal Vasko40702732017-10-25 11:43:23 +02001008
1009 col = strchr(str, ':');
1010 if (col) {
1011 *col = '\0';
1012 ++col;
1013 }
1014
1015 /* first node */
Michal Vasko25095332017-11-14 09:31:24 +01001016 if (first) {
Michal Vasko40702732017-10-25 11:43:23 +02001017 if (!col) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001018 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_NONE, NULL);
Michal Vasko40702732017-10-25 11:43:23 +02001019 goto error;
1020 }
1021
1022 cur_mod = ly_ctx_get_module(ctx, str, NULL, 0);
1023 if (!cur_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001024 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko40702732017-10-25 11:43:23 +02001025 goto error;
1026 }
Michal Vasko25095332017-11-14 09:31:24 +01001027
1028 first = 0;
Michal Vasko40702732017-10-25 11:43:23 +02001029 }
1030
1031 if (((col ? col[0] : str[0]) == '.') || ((col ? col[0] : str[0]) == '*')) {
Michal Vasko25095332017-11-14 09:31:24 +01001032 free(str);
1033 str = NULL;
1034
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001035 if (end_token) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001036 LOGERR(ctx, LY_EINVAL, "Invalid path used (%s in a subexpression).", str);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001037 goto error;
1038 }
Michal Vasko40702732017-10-25 11:43:23 +02001039
Michal Vasko25095332017-11-14 09:31:24 +01001040 /* we can no longer evaluate the path, so just copy the rest */
1041 path_lost = 1;
Michal Vasko53b7da02018-02-13 15:28:42 +01001042 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
Michal Vasko25095332017-11-14 09:31:24 +01001043 goto error;
1044 }
1045 break;
Michal Vasko40702732017-10-25 11:43:23 +02001046 }
1047
1048 /* create schema path for this data node */
1049 node = NULL;
Michal Vaskocb45f472018-02-12 10:47:42 +01001050 while ((node = lys_getnext(node, parent, cur_mod, LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko40702732017-10-25 11:43:23 +02001051 if (strcmp(node->name, col ? col : str)) {
1052 continue;
1053 }
1054
1055 if (col && strcmp(lys_node_module(node)->name, str)) {
1056 continue;
1057 }
1058 if (!col && (lys_node_module(node) != lys_node_module(parent))) {
1059 continue;
1060 }
1061
1062 /* determine how deep the node actually is, we must generate the path from the highest parent */
Michal Vasko1e07eae2017-11-01 08:47:44 +01001063 j = 0;
1064 node2 = node;
1065 while (node2 != parent) {
1066 node2 = lys_parent(node2);
1067 if (!node2 || (node2->nodetype != LYS_USES)) {
1068 ++j;
1069 }
1070 }
Michal Vasko40702732017-10-25 11:43:23 +02001071
1072 /* first node, do not print '/' */
1073 slash = 0;
1074 while (j) {
Michal Vasko1e07eae2017-11-01 08:47:44 +01001075 k = j - 1;
1076 node2 = node;
1077 while (k) {
1078 node2 = lys_parent(node2);
Michal Vasko80389542018-02-08 14:35:32 +01001079 assert(node2);
1080 if (node2->nodetype != LYS_USES) {
Michal Vasko1e07eae2017-11-01 08:47:44 +01001081 --k;
1082 }
1083 }
Michal Vasko40702732017-10-25 11:43:23 +02001084
1085 if ((lys_node_module(node2) != cur_mod) || !parent) {
1086 /* module name and node name */
1087 len = slash + strlen(lys_node_module(node2)->name) + 1 + strlen(node2->name);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001088 *out = ly_realloc(*out, *out_used + len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001089 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001090 sprintf(*out + *out_used - 1, "%s%s:%s", slash ? "/" : "", lys_node_module(node2)->name, node2->name);
1091 *out_used += len;
Michal Vasko40702732017-10-25 11:43:23 +02001092 } else {
1093 /* only node name */
1094 len = slash + strlen(node2->name);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001095 *out = ly_realloc(*out, *out_used + len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001096 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001097 sprintf(*out + *out_used - 1, "%s%s", slash ? "/" : "", node2->name);
1098 *out_used += len;
Michal Vasko40702732017-10-25 11:43:23 +02001099 }
1100
1101 slash = 1;
1102 --j;
1103 }
1104
1105 break;
1106 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001107 if (!node) {
1108 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, col ? col : str);
1109 goto error;
1110 }
Michal Vasko40702732017-10-25 11:43:23 +02001111
Michal Vasko25095332017-11-14 09:31:24 +01001112 /* copy any whitespaces */
1113 for (len = 0; isspace(exp->expr[exp->expr_pos[*cur_exp] + exp->tok_len[*cur_exp] + len]); ++len);
1114 if (len) {
1115 *out = ly_realloc(*out, *out_used + len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001116 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
Michal Vasko25095332017-11-14 09:31:24 +01001117 sprintf(*out + *out_used - 1, "%*s", len, " ");
1118 *out_used += len;
1119 }
1120
Michal Vasko40702732017-10-25 11:43:23 +02001121 /* next iteration */
1122 free(str);
1123 str = NULL;
1124 parent = node;
1125 break;
Michal Vasko25095332017-11-14 09:31:24 +01001126 case LYXP_TOKEN_COMMA:
1127 case LYXP_TOKEN_OPERATOR_LOG:
1128 case LYXP_TOKEN_OPERATOR_COMP:
1129 case LYXP_TOKEN_OPERATOR_MATH:
1130 case LYXP_TOKEN_OPERATOR_UNI:
1131 /* reset the processing */
1132 first = 1;
1133 path_lost = 0;
1134 parent = orig_parent;
1135
1136 /* fallthrough */
Michal Vasko40702732017-10-25 11:43:23 +02001137 case LYXP_TOKEN_OPERATOR_PATH:
Michal Vasko25095332017-11-14 09:31:24 +01001138 if ((exp->tokens[*cur_exp] == LYXP_TOKEN_OPERATOR_PATH) && (exp->tok_len[*cur_exp] == 2)) {
1139 /* we can no longer evaluate the path further */
1140 path_lost = 1;
1141 }
1142 /* fallthrough */
1143 case LYXP_TOKEN_NODETYPE:
1144 case LYXP_TOKEN_FUNCNAME:
1145 case LYXP_TOKEN_LITERAL:
1146 case LYXP_TOKEN_NUMBER:
Michal Vasko40702732017-10-25 11:43:23 +02001147 /* just copy it */
Michal Vasko53b7da02018-02-13 15:28:42 +01001148 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
Michal Vasko25095332017-11-14 09:31:24 +01001149 goto error;
1150 }
Michal Vasko40702732017-10-25 11:43:23 +02001151 break;
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001152 case LYXP_TOKEN_BRACK1:
Michal Vasko25095332017-11-14 09:31:24 +01001153 case LYXP_TOKEN_PAR1:
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001154 if (ly_path_data2schema_subexp(ctx, parent, cur_mod, exp, cur_exp, out, out_used)) {
1155 goto error;
1156 }
1157 break;
Michal Vasko40702732017-10-25 11:43:23 +02001158 default:
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001159 if (end_token && (exp->tokens[*cur_exp] == end_token)) {
Michal Vasko25095332017-11-14 09:31:24 +01001160 /* we are done (with this subexpression) */
Michal Vasko53b7da02018-02-13 15:28:42 +01001161 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
Michal Vasko25095332017-11-14 09:31:24 +01001162 goto error;
1163 }
1164
1165 return 0;
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001166 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001167 LOGERR(ctx, LY_EINVAL, "Invalid token used (%.*s).", exp->tok_len[*cur_exp], exp->expr + exp->expr_pos[*cur_exp]);
Michal Vasko40702732017-10-25 11:43:23 +02001168 goto error;
1169 }
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001170
1171 ++(*cur_exp);
1172 }
1173
1174 if (end_token) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001175 LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001176 return -1;
1177 }
1178
1179 return 0;
1180
1181error:
1182 free(str);
1183 return -1;
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001184}
1185
1186API char *
Michal Vasko53b7da02018-02-13 15:28:42 +01001187ly_path_data2schema(struct ly_ctx *ctx, const char *data_path)
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001188{
1189 struct lyxp_expr *exp;
PavolVicanb28bbff2018-02-21 00:44:02 +01001190 uint16_t out_used, cur_exp = 0;
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001191 char *out;
PavolVican195cf392018-02-23 13:24:45 +01001192 int r, mod_name_len, nam_len, is_relative = -1;
PavolVicanb28bbff2018-02-21 00:44:02 +01001193 const char *mod_name, *name;
1194 const struct lys_module *mod = NULL;
1195 const struct lys_node *parent = NULL;
1196 char *str;
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001197
1198 if (!ctx || !data_path) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001199 LOGARG;
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001200 return NULL;
1201 }
1202
PavolVican195cf392018-02-23 13:24:45 +01001203 if ((r = parse_schema_nodeid(data_path, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
PavolVicanb28bbff2018-02-21 00:44:02 +01001204 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, data_path[-r], &data_path[-r]);
1205 return NULL;
1206 }
1207
1208 if (name[0] == '#') {
1209 if (is_relative) {
1210 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1211 return NULL;
1212 }
1213
1214 ++name;
1215 --nam_len;
1216
1217 if (!mod_name) {
1218 str = strndup(data_path, (name + nam_len) - data_path);
1219 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, str);
1220 free(str);
1221 return NULL;
1222 }
1223
1224 str = strndup(mod_name, mod_name_len);
1225 if (!str) {
1226 LOGMEM(ctx);
1227 return NULL;
1228 }
1229 mod = ly_ctx_get_module(ctx, str, NULL, 1);
1230 free(str);
1231 if (!mod) {
1232 str = strndup(data_path, (mod_name + mod_name_len) - data_path);
1233 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1234 free(str);
1235 return NULL;
1236 }
1237
1238 parent = lyp_get_yang_data_template(mod, name, nam_len);
1239 if (!parent) {
1240 str = strndup(data_path, (name + nam_len) - data_path);
1241 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1242 free(str);
1243 return NULL;
1244 }
1245
1246 out_used = (name + nam_len) - data_path + 1;
1247 out = malloc(out_used);
1248 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
1249 memcpy(out, data_path, out_used -1);
1250 data_path += r;
1251 } else {
1252 out_used = 1;
1253 out = malloc(1);
1254 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
1255 }
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001256
Michal Vasko53b7da02018-02-13 15:28:42 +01001257 exp = lyxp_parse_expr(ctx, data_path);
Michal Vaskoee10f8c2017-10-25 14:47:05 +02001258 if (!exp) {
1259 free(out);
1260 return NULL;
1261 }
1262
PavolVicanb28bbff2018-02-21 00:44:02 +01001263 if (parent) {
1264 if (ly_path_data2schema_subexp(ctx, parent, mod, exp, &cur_exp, &out, &out_used)) {
1265 free(out);
1266 out = NULL;
1267 }
1268 } else {
1269 if (ly_path_data2schema_subexp(ctx, NULL, NULL, exp, &cur_exp, &out, &out_used)) {
1270 free(out);
1271 out = NULL;
1272 }
Michal Vasko40702732017-10-25 11:43:23 +02001273 }
1274
1275 lyxp_expr_free(exp);
1276 return out;
Michal Vasko40702732017-10-25 11:43:23 +02001277}
1278
Michal Vaskoe3886bb2017-01-02 11:33:28 +01001279int
1280ly_new_node_validity(const struct lys_node *schema)
1281{
1282 int validity;
1283
1284 validity = LYD_VAL_OK;
1285 switch (schema->nodetype) {
1286 case LYS_LEAF:
1287 case LYS_LEAFLIST:
1288 if (((struct lys_node_leaf *)schema)->type.base == LY_TYPE_LEAFREF) {
1289 validity |= LYD_VAL_LEAFREF;
1290 }
1291 validity |= LYD_VAL_MAND;
1292 break;
1293 case LYS_LIST:
1294 validity |= LYD_VAL_UNIQUE;
1295 /* fallthrough */
1296 case LYS_CONTAINER:
1297 case LYS_NOTIF:
1298 case LYS_RPC:
1299 case LYS_ACTION:
1300 case LYS_ANYXML:
1301 case LYS_ANYDATA:
1302 validity |= LYD_VAL_MAND;
1303 break;
1304 default:
1305 break;
1306 }
1307
1308 return validity;
1309}
1310
Michal Vasko253035f2015-12-17 16:58:13 +01001311void *
1312ly_realloc(void *ptr, size_t size)
1313{
1314 void *new_mem;
1315
1316 new_mem = realloc(ptr, size);
1317 if (!new_mem) {
1318 free(ptr);
1319 }
1320
1321 return new_mem;
Radek Krejci8b5924d2016-01-04 15:12:26 +01001322}
Radek Krejcie51396d2016-02-17 09:27:00 +01001323
1324int
Radek Krejci749190d2016-02-18 16:26:25 +01001325ly_strequal_(const char *s1, const char *s2)
Radek Krejcie51396d2016-02-17 09:27:00 +01001326{
1327 if (s1 == s2) {
1328 return 1;
1329 } else if (!s1 || !s2) {
1330 return 0;
1331 } else {
1332 for ( ; *s1 == *s2; s1++, s2++) {
1333 if (*s1 == '\0') {
1334 return 1;
1335 }
1336 }
1337 return 0;
1338 }
1339}
Michal Vasko4d1f0482016-09-19 14:35:06 +02001340
1341int64_t
1342dec_pow(uint8_t exp)
1343{
1344 int64_t ret = 1;
1345 uint8_t i;
1346
1347 for (i = 0; i < exp; ++i) {
1348 ret *= 10;
1349 }
1350
1351 return ret;
1352}
1353
1354int
1355dec64cmp(int64_t num1, uint8_t dig1, int64_t num2, uint8_t dig2)
1356{
1357 if (dig1 < dig2) {
1358 num2 /= dec_pow(dig2 - dig1);
1359 } else if (dig1 > dig2) {
1360 num1 /= dec_pow(dig1 - dig2);
1361 }
1362
1363 if (num1 == num2) {
1364 return 0;
1365 }
1366 return (num1 > num2 ? 1 : -1);
1367}