Radek Krejci | 9b4ca39 | 2015-04-10 08:31:27 +0200 | [diff] [blame] | 1 | /** |
| 2 | * @file common.c |
| 3 | * @author Radek Krejci <rkrejci@cesnet.cz> |
| 4 | * @brief common libyang routines implementations |
| 5 | * |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 6 | * Copyright (c) 2015 - 2017 CESNET, z.s.p.o. |
Radek Krejci | 9b4ca39 | 2015-04-10 08:31:27 +0200 | [diff] [blame] | 7 | * |
Radek Krejci | 54f6fb3 | 2016-02-24 12:56:39 +0100 | [diff] [blame] | 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 |
Michal Vasko | 8de098c | 2016-02-26 10:00:25 +0100 | [diff] [blame] | 11 | * |
Radek Krejci | 54f6fb3 | 2016-02-24 12:56:39 +0100 | [diff] [blame] | 12 | * https://opensource.org/licenses/BSD-3-Clause |
Radek Krejci | 9b4ca39 | 2015-04-10 08:31:27 +0200 | [diff] [blame] | 13 | */ |
Radek Krejci | 7136a8e | 2015-08-17 13:37:30 +0200 | [diff] [blame] | 14 | |
Radek Krejci | 8b5924d | 2016-01-04 15:12:26 +0100 | [diff] [blame] | 15 | #define _GNU_SOURCE |
| 16 | |
Michal Vasko | 9286afd | 2015-07-14 15:27:59 +0200 | [diff] [blame] | 17 | #include <assert.h> |
Michal Vasko | 9286afd | 2015-07-14 15:27:59 +0200 | [diff] [blame] | 18 | #include <ctype.h> |
Radek Krejci | 3d42f5e | 2016-02-08 12:22:27 +0100 | [diff] [blame] | 19 | #include <errno.h> |
| 20 | #include <limits.h> |
Radek Krejci | 7d9f46a | 2016-01-29 13:53:18 +0100 | [diff] [blame] | 21 | #include <pthread.h> |
Radek Krejci | 3d42f5e | 2016-02-08 12:22:27 +0100 | [diff] [blame] | 22 | #include <string.h> |
| 23 | #include <stdlib.h> |
| 24 | #include <sys/syscall.h> |
Radek Krejci | fd8c59b | 2016-02-05 15:40:20 +0100 | [diff] [blame] | 25 | #include <sys/types.h> |
Radek Krejci | fd8c59b | 2016-02-05 15:40:20 +0100 | [diff] [blame] | 26 | #include <unistd.h> |
Radek Krejci | 9b4ca39 | 2015-04-10 08:31:27 +0200 | [diff] [blame] | 27 | |
| 28 | #include "common.h" |
Michal Vasko | 921eb6b | 2017-10-13 10:01:39 +0200 | [diff] [blame] | 29 | #include "parser.h" |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 30 | #include "xpath.h" |
Michal Vasko | f53187d | 2017-01-13 13:23:14 +0100 | [diff] [blame] | 31 | #include "context.h" |
Radek Krejci | 9b4ca39 | 2015-04-10 08:31:27 +0200 | [diff] [blame] | 32 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 33 | THREAD_LOCAL enum int_log_opts log_opt; |
| 34 | THREAD_LOCAL int8_t ly_errno_glob; |
Radek Krejci | fd8c59b | 2016-02-05 15:40:20 +0100 | [diff] [blame] | 35 | |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 36 | API LY_ERR * |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 37 | ly_errno_glob_address(void) |
Radek Krejci | 1d7f8d2 | 2016-02-08 14:15:51 +0100 | [diff] [blame] | 38 | { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 39 | return (LY_ERR *)&ly_errno_glob; |
Radek Krejci | 1d7f8d2 | 2016-02-08 14:15:51 +0100 | [diff] [blame] | 40 | } |
| 41 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 42 | API LY_VECODE |
| 43 | ly_vecode(const struct ly_ctx *ctx) |
Radek Krejci | 7d9f46a | 2016-01-29 13:53:18 +0100 | [diff] [blame] | 44 | { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 45 | struct ly_err_item *i; |
| 46 | |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 47 | i = ly_err_first(ctx); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 48 | if (i) { |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 49 | return i->prev->vecode; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 50 | } |
| 51 | |
| 52 | return 0; |
Radek Krejci | 386714d | 2016-02-15 10:24:30 +0100 | [diff] [blame] | 53 | } |
| 54 | |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 55 | API const char * |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 56 | ly_errmsg(const struct ly_ctx *ctx) |
Radek Krejci | 386714d | 2016-02-15 10:24:30 +0100 | [diff] [blame] | 57 | { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 58 | struct ly_err_item *i; |
| 59 | |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 60 | i = ly_err_first(ctx); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 61 | if (i) { |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 62 | return i->prev->msg; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | return NULL; |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 66 | } |
Radek Krejci | 386714d | 2016-02-15 10:24:30 +0100 | [diff] [blame] | 67 | |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 68 | API const char * |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 69 | ly_errpath(const struct ly_ctx *ctx) |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 70 | { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 71 | struct ly_err_item *i; |
| 72 | |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 73 | i = ly_err_first(ctx); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 74 | if (i) { |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 75 | return i->prev->path; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | return NULL; |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 79 | } |
Radek Krejci | 386714d | 2016-02-15 10:24:30 +0100 | [diff] [blame] | 80 | |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 81 | API const char * |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 82 | ly_errapptag(const struct ly_ctx *ctx) |
Michal Vasko | 4814fb0 | 2017-08-17 14:49:38 +0200 | [diff] [blame] | 83 | { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 84 | struct ly_err_item *i; |
| 85 | |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 86 | i = ly_err_first(ctx); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 87 | if (i) { |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 88 | return i->prev->apptag; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | return NULL; |
| 92 | } |
| 93 | |
| 94 | API struct ly_err_item * |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 95 | ly_err_first(const struct ly_ctx *ctx) |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 96 | { |
Michal Vasko | a93b4bb | 2018-02-14 13:59:52 +0100 | [diff] [blame] | 97 | if (!ctx) { |
| 98 | return NULL; |
| 99 | } |
| 100 | |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 101 | return pthread_getspecific(ctx->errlist_key); |
Radek Krejci | 7d9f46a | 2016-01-29 13:53:18 +0100 | [diff] [blame] | 102 | } |
| 103 | |
Radek Krejci | 2467a49 | 2016-10-24 15:16:59 +0200 | [diff] [blame] | 104 | void |
Radek Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 105 | ly_err_free(void *ptr) |
Radek Krejci | 2467a49 | 2016-10-24 15:16:59 +0200 | [diff] [blame] | 106 | { |
| 107 | struct ly_err_item *i, *next; |
| 108 | |
Radek Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 109 | /* clean the error list */ |
| 110 | for (i = (struct ly_err_item *)ptr; i; i = next) { |
Radek Krejci | 2467a49 | 2016-10-24 15:16:59 +0200 | [diff] [blame] | 111 | next = i->next; |
| 112 | free(i->msg); |
| 113 | free(i->path); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 114 | free(i->apptag); |
Radek Krejci | 2467a49 | 2016-10-24 15:16:59 +0200 | [diff] [blame] | 115 | free(i); |
| 116 | } |
Radek Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 117 | } |
| 118 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 119 | API void |
| 120 | ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem) |
Radek Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 121 | { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 122 | struct ly_err_item *i, *first; |
Radek Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 123 | |
Michal Vasko | 10d6f2f | 2018-02-14 10:56:01 +0100 | [diff] [blame] | 124 | first = ly_err_first(ctx); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 125 | 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 Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 141 | pthread_setspecific(ctx->errlist_key, NULL); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 142 | /* also clean errno */ |
| 143 | ly_errno = LY_SUCCESS; |
Radek Krejci | cf74825 | 2017-09-04 11:11:14 +0200 | [diff] [blame] | 144 | } |
Radek Krejci | fbcbc09 | 2016-03-31 11:16:12 +0200 | [diff] [blame] | 145 | } |
| 146 | |
Radek Krejci | 15acd04 | 2016-02-05 17:09:39 +0100 | [diff] [blame] | 147 | #ifndef __USE_GNU |
| 148 | |
Radek Krejci | a8d111f | 2017-05-31 13:57:37 +0200 | [diff] [blame] | 149 | char * |
| 150 | get_current_dir_name(void) |
Radek Krejci | 15acd04 | 2016-02-05 17:09:39 +0100 | [diff] [blame] | 151 | { |
| 152 | char tmp[PATH_MAX]; |
Radek Krejci | a8d111f | 2017-05-31 13:57:37 +0200 | [diff] [blame] | 153 | char *retval; |
Radek Krejci | 15acd04 | 2016-02-05 17:09:39 +0100 | [diff] [blame] | 154 | |
Radek Krejci | a8d111f | 2017-05-31 13:57:37 +0200 | [diff] [blame] | 155 | if (getcwd(tmp, sizeof(tmp))) { |
| 156 | retval = strdup(tmp); |
Michal Vasko | ec19dcf | 2018-02-14 16:29:14 +0100 | [diff] [blame] | 157 | LY_CHECK_ERR_RETURN(!retval, LOGMEM(NULL), NULL); |
Radek Krejci | a8d111f | 2017-05-31 13:57:37 +0200 | [diff] [blame] | 158 | return retval; |
| 159 | } |
Radek Krejci | 15acd04 | 2016-02-05 17:09:39 +0100 | [diff] [blame] | 160 | return NULL; |
| 161 | } |
| 162 | |
| 163 | #endif |
| 164 | |
Michal Vasko | 9016b56 | 2015-08-18 16:25:21 +0200 | [diff] [blame] | 165 | const char * |
| 166 | strpbrk_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 Vasko | 1433a0c | 2015-08-19 11:02:38 +0200 | [diff] [blame] | 172 | if (*s == *sc) { |
| 173 | return s; |
| 174 | } |
Michal Vasko | 9016b56 | 2015-08-18 16:25:21 +0200 | [diff] [blame] | 175 | } |
| 176 | } |
| 177 | return s; |
| 178 | } |
| 179 | |
Michal Vasko | a7d0be6 | 2015-06-16 10:43:49 +0200 | [diff] [blame] | 180 | char * |
| 181 | strnchr(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 Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 190 | |
| 191 | const char * |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 192 | strnodetype(LYS_NODE type) |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 193 | { |
| 194 | switch (type) { |
Michal Vasko | 591e0b2 | 2015-08-13 13:53:43 +0200 | [diff] [blame] | 195 | case LYS_UNKNOWN: |
| 196 | return NULL; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 197 | case LYS_AUGMENT: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 198 | return "augment"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 199 | case LYS_CONTAINER: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 200 | return "container"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 201 | case LYS_CHOICE: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 202 | return "choice"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 203 | case LYS_LEAF: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 204 | return "leaf"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 205 | case LYS_LEAFLIST: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 206 | return "leaf-list"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 207 | case LYS_LIST: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 208 | return "list"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 209 | case LYS_ANYXML: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 210 | return "anyxml"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 211 | case LYS_GROUPING: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 212 | return "grouping"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 213 | case LYS_CASE: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 214 | return "case"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 215 | case LYS_INPUT: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 216 | return "input"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 217 | case LYS_OUTPUT: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 218 | return "output"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 219 | case LYS_NOTIF: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 220 | return "notification"; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 221 | case LYS_RPC: |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 222 | return "rpc"; |
Michal Vasko | 591e0b2 | 2015-08-13 13:53:43 +0200 | [diff] [blame] | 223 | case LYS_USES: |
| 224 | return "uses"; |
Michal Vasko | 44fb638 | 2016-06-29 11:12:27 +0200 | [diff] [blame] | 225 | case LYS_ACTION: |
| 226 | return "action"; |
Radek Krejci | bf2abff | 2016-08-23 15:51:52 +0200 | [diff] [blame] | 227 | case LYS_ANYDATA: |
| 228 | return "anydata"; |
Radek Krejci | f95b629 | 2017-02-13 15:57:37 +0100 | [diff] [blame] | 229 | case LYS_EXT: |
| 230 | return "extension instance"; |
Michal Vasko | fbbcdb5 | 2015-07-03 14:26:21 +0200 | [diff] [blame] | 231 | } |
| 232 | |
| 233 | return NULL; |
| 234 | } |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 235 | |
Michal Vasko | 30646e6 | 2015-10-09 14:02:09 +0200 | [diff] [blame] | 236 | const char * |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 237 | transform_module_name2import_prefix(const struct lys_module *module, const char *module_name) |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 238 | { |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 239 | uint16_t i; |
| 240 | |
Radek Krejci | d1b3dba | 2017-01-13 11:31:12 +0100 | [diff] [blame] | 241 | if (!module_name) { |
| 242 | return NULL; |
| 243 | } |
| 244 | |
Radek Krejci | c428344 | 2016-04-22 09:19:27 +0200 | [diff] [blame] | 245 | if (!strcmp(lys_main_module(module)->name, module_name)) { |
Michal Vasko | c271e97 | 2016-02-15 14:48:30 +0100 | [diff] [blame] | 246 | /* the same for module and submodule */ |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 247 | 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 Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 259 | static 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 Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 261 | const char ***namespaces, uint32_t *ns_count) |
| 262 | { |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 263 | const char *cur_expr, *end, *prefix, *literal; |
| 264 | char *name; |
| 265 | size_t name_len; |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 266 | const struct lys_module *mod = NULL, *prev_mod = NULL; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 267 | uint32_t i, j; |
| 268 | struct lyxp_expr *exp; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 269 | struct ly_ctx *ctx = module->ctx; |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 270 | |
Michal Vasko | 30646e6 | 2015-10-09 14:02:09 +0200 | [diff] [blame] | 271 | assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count))); |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 272 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 273 | exp = lyxp_parse_expr(ctx, expr); |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 274 | LY_CHECK_RETURN(!exp, 1); |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 275 | |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 276 | for (i = 0; i < exp->used; ++i) { |
| 277 | cur_expr = &exp->expr[exp->expr_pos[i]]; |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 278 | |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 279 | /* copy WS */ |
| 280 | if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) { |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 281 | strncpy(&(*out)[*out_used], end, cur_expr - end); |
| 282 | (*out_used) += cur_expr - end; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 283 | } |
| 284 | |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 285 | if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && ((end = strnchr(cur_expr, ':', exp->tok_len[i])) || inst_id)) { |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 286 | /* get the module */ |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 287 | if (!schema) { |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 288 | if (end) { |
| 289 | name_len = end - cur_expr; |
| 290 | name = strndup(cur_expr, name_len); |
Michal Vasko | d864d4c | 2017-12-06 09:59:29 +0100 | [diff] [blame] | 291 | 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 Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 299 | free(name); |
| 300 | if (!mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 301 | LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr); |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 302 | goto error; |
| 303 | } |
| 304 | prev_mod = mod; |
| 305 | } else { |
| 306 | mod = prev_mod; |
| 307 | if (!mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 308 | LOGINT(ctx); |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 309 | goto error; |
| 310 | } |
| 311 | name_len = 0; |
| 312 | end = cur_expr; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 313 | } |
| 314 | prefix = mod->prefix; |
| 315 | } else { |
Radek Krejci | d1507ca | 2017-08-09 13:09:41 +0200 | [diff] [blame] | 316 | if (end) { |
| 317 | name_len = end - cur_expr; |
| 318 | } else { |
| 319 | name_len = strlen(cur_expr); |
| 320 | end = cur_expr; |
| 321 | } |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 322 | name = strndup(cur_expr, name_len); |
| 323 | prefix = transform_module_name2import_prefix(module, name); |
| 324 | free(name); |
| 325 | if (!prefix) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 326 | LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 327 | 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 341 | LY_CHECK_ERR_GOTO(!(*prefixes), LOGMEM(ctx), error); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 342 | *namespaces = ly_realloc(*namespaces, *ns_count * sizeof **namespaces); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 343 | LY_CHECK_ERR_GOTO(!(*namespaces), LOGMEM(ctx), error); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 344 | (*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 Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 350 | *out_size += strlen(prefix) + 1 - name_len; |
| 351 | *out = ly_realloc(*out, *out_size); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 352 | LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 353 | |
| 354 | /* copy the model name */ |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 355 | strcpy(&(*out)[*out_used], prefix); |
| 356 | *out_used += strlen(prefix); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 357 | |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 358 | if (!name_len) { |
| 359 | /* we are adding the prefix, so also ':' */ |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 360 | (*out)[*out_used] = ':'; |
| 361 | ++(*out_used); |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 362 | } |
| 363 | |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 364 | /* copy the rest */ |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 365 | strncpy(&(*out)[*out_used], end, exp->tok_len[i] - name_len); |
| 366 | *out_used += exp->tok_len[i] - name_len; |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 367 | } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) { |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 368 | /* 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 Pan | 53e027f | 2018-02-06 14:16:57 +0800 | [diff] [blame] | 376 | if (_transform_json2xml_subexp(module, literal, out, out_used, out_size, schema, inst_id, prefixes, namespaces, ns_count)) { |
Michal Vasko | 91b2dcc | 2018-01-25 10:07:37 +0100 | [diff] [blame] | 377 | strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2); |
| 378 | *out_used += exp->tok_len[i] - 2; |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 379 | } |
| 380 | |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 381 | lydict_remove(module->ctx, literal); |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 382 | |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 383 | /* copy end quote */ |
| 384 | (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1]; |
| 385 | ++(*out_used); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 386 | } else { |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 387 | strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]); |
| 388 | *out_used += exp->tok_len[i]; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 389 | } |
| 390 | } |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 391 | |
Michal Vasko | 89afc11 | 2017-03-16 13:57:28 +0100 | [diff] [blame] | 392 | lyxp_expr_free(exp); |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 393 | return 0; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 394 | |
| 395 | error: |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 396 | if (!schema && ns_count) { |
| 397 | free(*prefixes); |
| 398 | free(*namespaces); |
| 399 | } |
Michal Vasko | 89afc11 | 2017-03-16 13:57:28 +0100 | [diff] [blame] | 400 | lyxp_expr_free(exp); |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 401 | return 1; |
| 402 | } |
| 403 | |
| 404 | static 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 Pan | 24189d0 | 2018-01-30 15:38:24 +0800 | [diff] [blame] | 414 | if (ns_count) { |
| 415 | *ns_count = 0; |
| 416 | *prefixes = NULL; |
| 417 | *namespaces = NULL; |
| 418 | } |
| 419 | |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 420 | 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 427 | LY_CHECK_ERR_RETURN(!out, LOGMEM(module->ctx), NULL); |
Derek Pan | 57e0f1e | 2018-01-25 16:08:17 +0800 | [diff] [blame] | 428 | 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 Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 437 | return NULL; |
| 438 | } |
| 439 | |
| 440 | const char * |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 441 | transform_json2xml(const struct lys_module *module, const char *expr, int inst_id, const char ***prefixes, |
| 442 | const char ***namespaces, uint32_t *ns_count) |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 443 | { |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 444 | return _transform_json2xml(module, expr, 0, inst_id, prefixes, namespaces, ns_count); |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 445 | } |
| 446 | |
| 447 | const char * |
| 448 | transform_json2schema(const struct lys_module *module, const char *expr) |
| 449 | { |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 450 | return _transform_json2xml(module, expr, 1, 0, NULL, NULL, NULL); |
Michal Vasko | ea73354 | 2016-02-05 13:14:23 +0100 | [diff] [blame] | 451 | } |
| 452 | |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 453 | static int |
| 454 | transform_xml2json_subexp(struct ly_ctx *ctx, const char *expr, char **out, size_t *out_used, size_t *out_size, |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 455 | struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb) |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 456 | { |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 457 | const char *end, *cur_expr, *literal; |
| 458 | char *prefix; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 459 | uint16_t i; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 460 | enum int_log_opts prev_ilo; |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 461 | size_t pref_len; |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 462 | const struct lys_module *mod, *prev_mod = NULL; |
Michal Vasko | 1e62a09 | 2015-12-01 12:27:20 +0100 | [diff] [blame] | 463 | const struct lyxml_ns *ns; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 464 | struct lyxp_expr *exp; |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 465 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 466 | exp = lyxp_parse_expr(ctx, expr); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 467 | if (!exp) { |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 468 | return 1; |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 469 | } |
| 470 | |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 471 | 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 Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 476 | strncpy(&(*out)[*out_used], end, cur_expr - end); |
| 477 | (*out_used) += cur_expr - end; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 478 | } |
| 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 485 | LOGMEM(ctx); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 486 | goto error; |
| 487 | } |
| 488 | ns = lyxml_get_ns(xml, prefix); |
| 489 | free(prefix); |
| 490 | if (!ns) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 491 | 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 Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 493 | goto error; |
| 494 | } |
Michal Vasko | d864d4c | 2017-12-06 09:59:29 +0100 | [diff] [blame] | 495 | mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 0); |
Michal Vasko | f53187d | 2017-01-13 13:23:14 +0100 | [diff] [blame] | 496 | 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 Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 503 | if (!mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 504 | 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 Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 506 | goto error; |
| 507 | } |
| 508 | |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 509 | if (!inst_id || (mod != prev_mod)) { |
| 510 | /* adjust out size (it can even decrease in some strange cases) */ |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 511 | *out_size += strlen(mod->name) - pref_len; |
| 512 | *out = ly_realloc(*out, *out_size); |
| 513 | if (!(*out)) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 514 | LOGMEM(ctx); |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 515 | goto error; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 516 | } |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 517 | |
| 518 | /* copy the model name */ |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 519 | strcpy(&(*out)[*out_used], mod->name); |
| 520 | *out_used += strlen(mod->name); |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 521 | } else { |
| 522 | /* skip ':' */ |
| 523 | ++end; |
| 524 | ++pref_len; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 525 | } |
| 526 | |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 527 | /* remember previous model name */ |
| 528 | prev_mod = mod; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 529 | |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 530 | /* copy the rest */ |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 531 | strncpy(&(*out)[*out_used], end, exp->tok_len[i] - pref_len); |
| 532 | *out_used += exp->tok_len[i] - pref_len; |
Michal Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 533 | } else if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && inst_id) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 534 | 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 Vasko | 1b6ca96 | 2017-08-03 14:23:09 +0200 | [diff] [blame] | 536 | goto error; |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 537 | } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) { |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 538 | /* 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 545 | /* 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 Vasko | 91b2dcc | 2018-01-25 10:07:37 +0100 | [diff] [blame] | 549 | strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2); |
| 550 | *out_used += exp->tok_len[i] - 2; |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 551 | } |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 552 | log_opt = prev_ilo; |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 553 | |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 554 | lydict_remove(ctx, literal); |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 555 | |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 556 | /* copy end quote */ |
| 557 | (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1]; |
| 558 | ++(*out_used); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 559 | } else { |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 560 | strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]); |
| 561 | *out_used += exp->tok_len[i]; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 562 | } |
| 563 | } |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 564 | |
Michal Vasko | 89afc11 | 2017-03-16 13:57:28 +0100 | [diff] [blame] | 565 | lyxp_expr_free(exp); |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 566 | return 0; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 567 | |
| 568 | error: |
Michal Vasko | 89afc11 | 2017-03-16 13:57:28 +0100 | [diff] [blame] | 569 | lyxp_expr_free(exp); |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 570 | return 1; |
| 571 | } |
| 572 | |
| 573 | const char * |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 574 | transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb) |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 575 | { |
| 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 583 | LOGMEM(ctx); |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 584 | return NULL; |
| 585 | } |
| 586 | out_used = 0; |
| 587 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 588 | ret = transform_xml2json_subexp(ctx, expr, &out, &out_used, &out_size, xml, inst_id, use_ctx_data_clb); |
Michal Vasko | 6be951e | 2018-01-23 13:20:51 +0100 | [diff] [blame] | 589 | if (!ret) { |
| 590 | out[out_used] = '\0'; |
| 591 | return lydict_insert_zc(ctx, out); |
| 592 | } |
| 593 | |
| 594 | free(out); |
Michal Vasko | 2e28620 | 2015-10-09 12:54:27 +0200 | [diff] [blame] | 595 | return NULL; |
| 596 | } |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 597 | |
Michal Vasko | 065c565 | 2018-03-08 15:35:21 +0100 | [diff] [blame] | 598 | API char * |
| 599 | ly_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 Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 618 | const char * |
Radek Krejci | 48464ed | 2016-03-17 15:44:09 +0100 | [diff] [blame] | 619 | transform_schema2json(const struct lys_module *module, const char *expr) |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 620 | { |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 621 | const char *end, *cur_expr, *ptr; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 622 | char *out; |
| 623 | uint16_t i; |
| 624 | size_t out_size, out_used, pref_len; |
| 625 | const struct lys_module *mod; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 626 | struct ly_ctx *ctx = module->ctx; |
Radek Krejci | 5717e43 | 2016-11-04 10:33:04 +0100 | [diff] [blame] | 627 | struct lyxp_expr *exp = NULL; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 628 | |
| 629 | out_size = strlen(expr) + 1; |
| 630 | out = malloc(out_size); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 631 | LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 632 | out_used = 0; |
| 633 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 634 | exp = lyxp_parse_expr(ctx, expr); |
Radek Krejci | a8d111f | 2017-05-31 13:57:37 +0200 | [diff] [blame] | 635 | LY_CHECK_ERR_GOTO(!exp, , error); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 636 | |
| 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 Vasko | 921eb6b | 2017-10-13 10:01:39 +0200 | [diff] [blame] | 649 | mod = lyp_get_module(module, cur_expr, pref_len, NULL, 0, 0); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 650 | if (!mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 651 | LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, pref_len, cur_expr); |
Radek Krejci | 5717e43 | 2016-11-04 10:33:04 +0100 | [diff] [blame] | 652 | goto error; |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 653 | } |
| 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 658 | LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 659 | |
| 660 | /* copy the model name */ |
| 661 | strcpy(&out[out_used], mod->name); |
| 662 | out_used += strlen(mod->name); |
| 663 | |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 664 | /* copy the rest */ |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 665 | 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 Vasko | 921eb6b | 2017-10-13 10:01:39 +0200 | [diff] [blame] | 675 | mod = lyp_get_module(module, ptr, pref_len, NULL, 0, 0); |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 676 | 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 680 | LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error); |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 681 | |
| 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 Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 697 | } 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 Vasko | 89afc11 | 2017-03-16 13:57:28 +0100 | [diff] [blame] | 704 | lyxp_expr_free(exp); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 705 | return lydict_insert_zc(module->ctx, out); |
| 706 | |
| 707 | error: |
| 708 | free(out); |
Michal Vasko | 89afc11 | 2017-03-16 13:57:28 +0100 | [diff] [blame] | 709 | lyxp_expr_free(exp); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 710 | return NULL; |
| 711 | } |
| 712 | |
| 713 | const char * |
| 714 | transform_iffeat_schema2json(const struct lys_module *module, const char *expr) |
| 715 | { |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 716 | const char *in, *id; |
| 717 | char *out, *col; |
| 718 | size_t out_size, out_used, id_len, rc; |
Michal Vasko | 1e62a09 | 2015-12-01 12:27:20 +0100 | [diff] [blame] | 719 | const struct lys_module *mod; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 720 | struct ly_ctx *ctx = module->ctx; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 721 | |
| 722 | in = expr; |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 723 | out_size = strlen(in) + 1; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 724 | out = malloc(out_size); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 725 | LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 726 | 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 Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 733 | out_used += strlen(in) + 1; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 734 | assert(out_size == out_used); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 735 | return lydict_insert_zc(ctx, out); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 736 | } |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 737 | id = strpbrk_backwards(col - 1, "/ [\'\"", (col - in) - 1); |
Michal Vasko | 56d082c | 2016-10-25 14:00:42 +0200 | [diff] [blame] | 738 | if ((id[0] == '/') || (id[0] == ' ') || (id[0] == '[') || (id[0] == '\'') || (id[0] == '\"')) { |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 739 | ++id; |
| 740 | } |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 741 | id_len = col - id; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 742 | rc = parse_identifier(id); |
| 743 | if (rc < id_len) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 744 | LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, id[rc], &id[rc]); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 745 | free(out); |
| 746 | return NULL; |
| 747 | } |
| 748 | |
| 749 | /* get the module */ |
Michal Vasko | 921eb6b | 2017-10-13 10:01:39 +0200 | [diff] [blame] | 750 | mod = lyp_get_module(module, id, id_len, NULL, 0, 0); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 751 | if (!mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 752 | LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, id_len, id); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 753 | free(out); |
| 754 | return NULL; |
| 755 | } |
| 756 | |
| 757 | /* adjust out size (it can even decrease in some strange cases) */ |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 758 | out_size += strlen(mod->name) - id_len; |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 759 | out = ly_realloc(out, out_size); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 760 | LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 761 | |
| 762 | /* copy the data before prefix */ |
Michal Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 763 | strncpy(&out[out_used], in, id - in); |
| 764 | out_used += id - in; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 765 | |
| 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 Vasko | 4b0727e | 2016-11-16 09:52:25 +0100 | [diff] [blame] | 775 | in = col + 1; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 776 | } |
| 777 | |
| 778 | /* unreachable */ |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 779 | LOGINT(ctx); |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 780 | return NULL; |
| 781 | } |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 782 | |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 783 | static int |
| 784 | transform_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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 791 | struct ly_ctx *ctx = cur_module->ctx; |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 792 | |
| 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 Vasko | e59c109 | 2017-12-12 09:49:21 +0100 | [diff] [blame] | 817 | if (*i >= exp->used) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 818 | LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL); |
Michal Vasko | e59c109 | 2017-12-12 09:49:21 +0100 | [diff] [blame] | 819 | return -1; |
| 820 | } |
| 821 | |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 822 | /* 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 830 | prev_mod = ly_ctx_get_module(ctx, name, NULL, 1); |
Radek Krejci | a62a9d1 | 2017-08-09 12:37:51 +0200 | [diff] [blame] | 831 | free(name); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 832 | if (!prev_mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 833 | LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len ? name_len : exp->tok_len[*i], cur_expr); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 834 | return -1; |
| 835 | } |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 836 | /* skip ":" */ |
| 837 | ++end; |
| 838 | ++name_len; |
| 839 | } else { |
| 840 | end = cur_expr; |
| 841 | name_len = 0; |
| 842 | } |
| 843 | |
Michal Vasko | 2a216f2 | 2018-05-14 10:15:27 +0200 | [diff] [blame] | 844 | /* 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 Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 846 | /* 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 849 | LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 850 | |
| 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 872 | mod = ly_ctx_get_module(ctx, name, NULL, 1); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 873 | 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 879 | LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 880 | |
| 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 | |
| 907 | char * |
| 908 | transform_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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 919 | LY_CHECK_ERR_RETURN(!out, LOGMEM(cur_module->ctx), NULL); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 920 | out_used = 0; |
| 921 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 922 | exp = lyxp_parse_expr(cur_module->ctx, expr); |
Michal Vasko | 5057671 | 2017-07-28 12:28:33 +0200 | [diff] [blame] | 923 | 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 | |
| 934 | error: |
| 935 | free(out); |
| 936 | lyxp_expr_free(exp); |
| 937 | return NULL; |
| 938 | } |
| 939 | |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 940 | static int |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 941 | ly_path_data2schema_copy_token(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t cur_exp, char **out, uint16_t *out_used) |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 942 | { |
| 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 947 | LY_CHECK_ERR_RETURN(!(*out), LOGMEM(ctx), -1); |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 948 | sprintf(*out + *out_used - 1, "%.*s", len, exp->expr + exp->expr_pos[cur_exp]); |
| 949 | *out_used += len; |
| 950 | |
| 951 | return 0; |
| 952 | } |
| 953 | |
| 954 | static int |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 955 | ly_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 Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 957 | { |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 958 | 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 Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 962 | int first, path_lost; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 963 | |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 964 | switch (exp->tokens[*cur_exp]) { |
| 965 | case LYXP_TOKEN_BRACK1: |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 966 | end_token = LYXP_TOKEN_BRACK2; |
| 967 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 968 | if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 969 | goto error; |
| 970 | } |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 971 | ++(*cur_exp); |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 972 | first = 0; |
| 973 | break; |
| 974 | case LYXP_TOKEN_PAR1: |
| 975 | end_token = LYXP_TOKEN_PAR2; |
| 976 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 977 | if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 978 | goto error; |
| 979 | } |
| 980 | ++(*cur_exp); |
| 981 | first = 0; |
| 982 | break; |
PavolVican | b28bbff | 2018-02-21 00:44:02 +0100 | [diff] [blame] | 983 | case LYXP_TOKEN_OPERATOR_PATH: |
| 984 | first = (orig_parent) ? 0 : 1; |
| 985 | break; |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 986 | default: |
| 987 | first = 1; |
| 988 | break; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 989 | } |
| 990 | |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 991 | path_lost = 0; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 992 | parent = orig_parent; |
| 993 | while (*cur_exp < exp->used) { |
| 994 | switch (exp->tokens[*cur_exp]) { |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 995 | case LYXP_TOKEN_DOT: |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 996 | case LYXP_TOKEN_DDOT: |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 997 | case LYXP_TOKEN_NAMETEST: |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 998 | if (path_lost) { |
| 999 | /* we do not know anything anymore, just copy it */ |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1000 | if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1001 | goto error; |
| 1002 | } |
| 1003 | break; |
| 1004 | } |
| 1005 | |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1006 | str = strndup(exp->expr + exp->expr_pos[*cur_exp], exp->tok_len[*cur_exp]); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1007 | LY_CHECK_ERR_GOTO(!str, LOGMEM(ctx), error); |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1008 | |
| 1009 | col = strchr(str, ':'); |
| 1010 | if (col) { |
| 1011 | *col = '\0'; |
| 1012 | ++col; |
| 1013 | } |
| 1014 | |
| 1015 | /* first node */ |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1016 | if (first) { |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1017 | if (!col) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1018 | LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_NONE, NULL); |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1019 | goto error; |
| 1020 | } |
| 1021 | |
| 1022 | cur_mod = ly_ctx_get_module(ctx, str, NULL, 0); |
| 1023 | if (!cur_mod) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1024 | LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str); |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1025 | goto error; |
| 1026 | } |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1027 | |
| 1028 | first = 0; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1029 | } |
| 1030 | |
| 1031 | if (((col ? col[0] : str[0]) == '.') || ((col ? col[0] : str[0]) == '*')) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1032 | free(str); |
| 1033 | str = NULL; |
| 1034 | |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1035 | if (end_token) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1036 | LOGERR(ctx, LY_EINVAL, "Invalid path used (%s in a subexpression).", str); |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1037 | goto error; |
| 1038 | } |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1039 | |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1040 | /* we can no longer evaluate the path, so just copy the rest */ |
| 1041 | path_lost = 1; |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1042 | if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1043 | goto error; |
| 1044 | } |
| 1045 | break; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1046 | } |
| 1047 | |
| 1048 | /* create schema path for this data node */ |
| 1049 | node = NULL; |
Michal Vasko | cb45f47 | 2018-02-12 10:47:42 +0100 | [diff] [blame] | 1050 | while ((node = lys_getnext(node, parent, cur_mod, LYS_GETNEXT_NOSTATECHECK))) { |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1051 | 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 Vasko | 1e07eae | 2017-11-01 08:47:44 +0100 | [diff] [blame] | 1063 | 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 Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1071 | |
| 1072 | /* first node, do not print '/' */ |
| 1073 | slash = 0; |
| 1074 | while (j) { |
Michal Vasko | 1e07eae | 2017-11-01 08:47:44 +0100 | [diff] [blame] | 1075 | k = j - 1; |
| 1076 | node2 = node; |
| 1077 | while (k) { |
| 1078 | node2 = lys_parent(node2); |
Michal Vasko | 8038954 | 2018-02-08 14:35:32 +0100 | [diff] [blame] | 1079 | assert(node2); |
| 1080 | if (node2->nodetype != LYS_USES) { |
Michal Vasko | 1e07eae | 2017-11-01 08:47:44 +0100 | [diff] [blame] | 1081 | --k; |
| 1082 | } |
| 1083 | } |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1084 | |
| 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 Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1088 | *out = ly_realloc(*out, *out_used + len); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1089 | LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error); |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1090 | sprintf(*out + *out_used - 1, "%s%s:%s", slash ? "/" : "", lys_node_module(node2)->name, node2->name); |
| 1091 | *out_used += len; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1092 | } else { |
| 1093 | /* only node name */ |
| 1094 | len = slash + strlen(node2->name); |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1095 | *out = ly_realloc(*out, *out_used + len); |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1096 | LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error); |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1097 | sprintf(*out + *out_used - 1, "%s%s", slash ? "/" : "", node2->name); |
| 1098 | *out_used += len; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1099 | } |
| 1100 | |
| 1101 | slash = 1; |
| 1102 | --j; |
| 1103 | } |
| 1104 | |
| 1105 | break; |
| 1106 | } |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1107 | if (!node) { |
| 1108 | LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, col ? col : str); |
| 1109 | goto error; |
| 1110 | } |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1111 | |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1112 | /* 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 Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1116 | LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error); |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1117 | sprintf(*out + *out_used - 1, "%*s", len, " "); |
| 1118 | *out_used += len; |
| 1119 | } |
| 1120 | |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1121 | /* next iteration */ |
| 1122 | free(str); |
| 1123 | str = NULL; |
| 1124 | parent = node; |
| 1125 | break; |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1126 | 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 Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1137 | case LYXP_TOKEN_OPERATOR_PATH: |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1138 | 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 Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1147 | /* just copy it */ |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1148 | if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1149 | goto error; |
| 1150 | } |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1151 | break; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1152 | case LYXP_TOKEN_BRACK1: |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1153 | case LYXP_TOKEN_PAR1: |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1154 | if (ly_path_data2schema_subexp(ctx, parent, cur_mod, exp, cur_exp, out, out_used)) { |
| 1155 | goto error; |
| 1156 | } |
| 1157 | break; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1158 | default: |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1159 | if (end_token && (exp->tokens[*cur_exp] == end_token)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1160 | /* we are done (with this subexpression) */ |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1161 | if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) { |
Michal Vasko | 2509533 | 2017-11-14 09:31:24 +0100 | [diff] [blame] | 1162 | goto error; |
| 1163 | } |
| 1164 | |
| 1165 | return 0; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1166 | } |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1167 | LOGERR(ctx, LY_EINVAL, "Invalid token used (%.*s).", exp->tok_len[*cur_exp], exp->expr + exp->expr_pos[*cur_exp]); |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1168 | goto error; |
| 1169 | } |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1170 | |
| 1171 | ++(*cur_exp); |
| 1172 | } |
| 1173 | |
| 1174 | if (end_token) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1175 | LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL); |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1176 | return -1; |
| 1177 | } |
| 1178 | |
| 1179 | return 0; |
| 1180 | |
| 1181 | error: |
| 1182 | free(str); |
| 1183 | return -1; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1184 | } |
| 1185 | |
| 1186 | API char * |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1187 | ly_path_data2schema(struct ly_ctx *ctx, const char *data_path) |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1188 | { |
| 1189 | struct lyxp_expr *exp; |
PavolVican | b28bbff | 2018-02-21 00:44:02 +0100 | [diff] [blame] | 1190 | uint16_t out_used, cur_exp = 0; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1191 | char *out; |
PavolVican | 195cf39 | 2018-02-23 13:24:45 +0100 | [diff] [blame] | 1192 | int r, mod_name_len, nam_len, is_relative = -1; |
PavolVican | b28bbff | 2018-02-21 00:44:02 +0100 | [diff] [blame] | 1193 | const char *mod_name, *name; |
| 1194 | const struct lys_module *mod = NULL; |
| 1195 | const struct lys_node *parent = NULL; |
| 1196 | char *str; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1197 | |
| 1198 | if (!ctx || !data_path) { |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1199 | LOGARG; |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1200 | return NULL; |
| 1201 | } |
| 1202 | |
PavolVican | 195cf39 | 2018-02-23 13:24:45 +0100 | [diff] [blame] | 1203 | if ((r = parse_schema_nodeid(data_path, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) { |
PavolVican | b28bbff | 2018-02-21 00:44:02 +0100 | [diff] [blame] | 1204 | 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 Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1256 | |
Michal Vasko | 53b7da0 | 2018-02-13 15:28:42 +0100 | [diff] [blame] | 1257 | exp = lyxp_parse_expr(ctx, data_path); |
Michal Vasko | ee10f8c | 2017-10-25 14:47:05 +0200 | [diff] [blame] | 1258 | if (!exp) { |
| 1259 | free(out); |
| 1260 | return NULL; |
| 1261 | } |
| 1262 | |
PavolVican | b28bbff | 2018-02-21 00:44:02 +0100 | [diff] [blame] | 1263 | 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 Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1273 | } |
| 1274 | |
| 1275 | lyxp_expr_free(exp); |
| 1276 | return out; |
Michal Vasko | 4070273 | 2017-10-25 11:43:23 +0200 | [diff] [blame] | 1277 | } |
| 1278 | |
Michal Vasko | e3886bb | 2017-01-02 11:33:28 +0100 | [diff] [blame] | 1279 | int |
| 1280 | ly_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 Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 1311 | void * |
| 1312 | ly_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 Krejci | 8b5924d | 2016-01-04 15:12:26 +0100 | [diff] [blame] | 1322 | } |
Radek Krejci | e51396d | 2016-02-17 09:27:00 +0100 | [diff] [blame] | 1323 | |
| 1324 | int |
Radek Krejci | 749190d | 2016-02-18 16:26:25 +0100 | [diff] [blame] | 1325 | ly_strequal_(const char *s1, const char *s2) |
Radek Krejci | e51396d | 2016-02-17 09:27:00 +0100 | [diff] [blame] | 1326 | { |
| 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 Vasko | 4d1f048 | 2016-09-19 14:35:06 +0200 | [diff] [blame] | 1340 | |
| 1341 | int64_t |
| 1342 | dec_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 | |
| 1354 | int |
| 1355 | dec64cmp(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 | } |