libyang 2.1.80
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
Loading...
Searching...
No Matches
node_instanceid.c
Go to the documentation of this file.
1
15#include "plugins_types.h"
16
17#include <stdint.h>
18#include <stdlib.h>
19
20#include "libyang.h"
21
22/* additional internal headers for some useful simple macros */
23#include "common.h"
24#include "compat.h"
25#include "path.h"
26#include "plugins_internal.h" /* LY_TYPE_*_STR */
27#include "xpath.h"
28
47static LY_ERR
48node_instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, void *prefix_data, char **str)
49{
50 LY_ERR ret = LY_SUCCESS;
52 char *result = NULL, quot;
53 const struct lys_module *mod = NULL;
54 ly_bool inherit_prefix = 0, d;
55 const char *strval;
56
57 if (!path) {
58 /* special path */
59 ret = ly_strcat(&result, "/");
60 goto cleanup;
61 }
62
63 switch (format) {
64 case LY_VALUE_XML:
65 case LY_VALUE_SCHEMA:
67 /* everything is prefixed */
68 inherit_prefix = 0;
69 break;
70 case LY_VALUE_CANON:
71 case LY_VALUE_JSON:
72 case LY_VALUE_LYB:
73 case LY_VALUE_STR_NS:
74 /* the same prefix is inherited and skipped */
75 inherit_prefix = 1;
76 break;
77 }
78
79 LY_ARRAY_FOR(path, u) {
80 /* new node */
81 if (!inherit_prefix || (mod != path[u].node->module)) {
82 mod = path[u].node->module;
83 ret = ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), path[u].node->name);
84 } else {
85 ret = ly_strcat(&result, "/%s", path[u].node->name);
86 }
87 LY_CHECK_GOTO(ret, cleanup);
88
89 /* node predicates */
90 LY_ARRAY_FOR(path[u].predicates, v) {
91 struct ly_path_predicate *pred = &path[u].predicates[v];
92
93 switch (pred->type) {
94 case LY_PATH_PREDTYPE_POSITION:
95 /* position predicate */
96 ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
97 break;
98 case LY_PATH_PREDTYPE_LIST:
99 /* key-predicate */
100 strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
101 &d, NULL);
102
103 /* default quote */
104 quot = '\'';
105 if (strchr(strval, quot)) {
106 quot = '"';
107 }
108 if (inherit_prefix) {
109 /* always the same prefix as the parent */
110 ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
111 } else {
112 ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
113 pred->key->name, quot, strval, quot);
114 }
115 if (d) {
116 free((char *)strval);
117 }
118 break;
119 case LY_PATH_PREDTYPE_LEAFLIST:
120 /* leaf-list-predicate */
121 strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
122 &d, NULL);
123
124 /* default quote */
125 quot = '\'';
126 if (strchr(strval, quot)) {
127 quot = '"';
128 }
129 ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
130 if (d) {
131 free((char *)strval);
132 }
133 break;
134 case LY_PATH_PREDTYPE_LIST_VAR:
135 /* key-predicate with a variable */
136 if (inherit_prefix) {
137 /* always the same prefix as the parent */
138 ret = ly_strcat(&result, "[%s=$%s]", pred->key->name, pred->variable);
139 } else {
140 ret = ly_strcat(&result, "[%s:%s=$%s]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
141 pred->key->name, pred->variable);
142 }
143 break;
144 }
145
146 LY_CHECK_GOTO(ret, cleanup);
147 }
148 }
149
150cleanup:
151 if (ret) {
152 free(result);
153 } else {
154 *str = result;
155 }
156 return ret;
157}
158
162static LY_ERR
163lyplg_type_store_node_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
164 uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
165 struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
166{
167 LY_ERR ret = LY_SUCCESS;
168 struct lyxp_expr *exp = NULL;
169 uint32_t prefix_opt = 0;
170 struct ly_path *path = NULL;
171 char *canon;
172
173 /* init storage */
174 memset(storage, 0, sizeof *storage);
175 storage->realtype = type;
176
177 /* check hints */
178 ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
179 LY_CHECK_GOTO(ret, cleanup);
180
181 if ((((char *)value)[0] == '/') && (value_len == 1)) {
182 /* special path */
183 goto store;
184 }
185
186 switch (format) {
187 case LY_VALUE_SCHEMA:
189 case LY_VALUE_XML:
190 prefix_opt = LY_PATH_PREFIX_MANDATORY;
191 break;
192 case LY_VALUE_CANON:
193 case LY_VALUE_LYB:
194 case LY_VALUE_JSON:
195 case LY_VALUE_STR_NS:
196 prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
197 break;
198 }
199
200 /* parse the value */
201 ret = ly_path_parse(ctx, ctx_node, value, value_len, 0, LY_PATH_BEGIN_ABSOLUTE, prefix_opt, LY_PATH_PRED_SIMPLE, &exp);
202 if (ret) {
203 ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
204 "Invalid node-instance-identifier \"%.*s\" value - syntax error.", (int)value_len, (char *)value);
205 goto cleanup;
206 }
207
208 if (options & LYPLG_TYPE_STORE_IMPLEMENT) {
209 /* implement all prefixes */
210 LY_CHECK_GOTO(ret = lys_compile_expr_implement(ctx, exp, format, prefix_data, 1, unres, NULL), cleanup);
211 }
212
213 /* resolve it on schema tree, use JSON format instead of LYB because for this type they are equal but for some
214 * nested types (such as numbers in predicates in the path) LYB would be invalid */
215 ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, (ctx_node && (ctx_node->flags & LYS_IS_OUTPUT)) ?
216 LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, 1, (format == LY_VALUE_LYB) ?
217 LY_VALUE_JSON : format, prefix_data, &path);
218 if (ret) {
219 ret = ly_err_new(err, ret, LYVE_DATA, NULL, NULL,
220 "Invalid node-instance-identifier \"%.*s\" value - semantic error.", (int)value_len, (char *)value);
221 goto cleanup;
222 }
223
224store:
225 /* store value */
226 storage->target = path;
227
228 /* store canonical value */
229 if (format == LY_VALUE_CANON) {
230 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
231 ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
232 options &= ~LYPLG_TYPE_STORE_DYNAMIC;
233 LY_CHECK_GOTO(ret, cleanup);
234 } else {
235 ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
236 LY_CHECK_GOTO(ret, cleanup);
237 }
238 } else {
239 /* JSON format with prefix is the canonical one */
240 ret = node_instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
241 LY_CHECK_GOTO(ret, cleanup);
242
243 ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
244 LY_CHECK_GOTO(ret, cleanup);
245 }
246
247cleanup:
248 lyxp_expr_free(ctx, exp);
249 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
250 free((void *)value);
251 }
252
253 if (ret) {
254 lyplg_type_free_instanceid(ctx, storage);
255 }
256 return ret;
257}
258
262static const void *
263lyplg_type_print_node_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
264 void *prefix_data, ly_bool *dynamic, size_t *value_len)
265{
266 char *ret;
267
268 if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
269 if (dynamic) {
270 *dynamic = 0;
271 }
272 if (value_len) {
273 *value_len = strlen(value->_canonical);
274 }
275 return value->_canonical;
276 }
277
278 /* print the value in the specific format */
279 if (node_instanceid_path2str(value->target, format, prefix_data, &ret)) {
280 return NULL;
281 }
282 *dynamic = 1;
283 if (value_len) {
284 *value_len = strlen(ret);
285 }
286 return ret;
287}
288
297 {
298 .module = "ietf-netconf-acm",
299 .revision = "2012-02-22",
300 .name = "node-instance-identifier",
301
302 .plugin.id = "libyang 2 - node-instance-identifier, version 1",
303 .plugin.store = lyplg_type_store_node_instanceid,
304 .plugin.validate = NULL,
305 .plugin.compare = lyplg_type_compare_instanceid,
306 .plugin.sort = NULL,
307 .plugin.print = lyplg_type_print_node_instanceid,
308 .plugin.duplicate = lyplg_type_dup_instanceid,
309 .plugin.free = lyplg_type_free_instanceid,
310 .plugin.lyb_data_len = -1,
311 },
312 {
313 .module = "ietf-netconf-acm",
314 .revision = "2018-02-14",
315 .name = "node-instance-identifier",
316
317 .plugin.id = "libyang 2 - node-instance-identifier, version 1",
318 .plugin.store = lyplg_type_store_node_instanceid,
319 .plugin.validate = NULL,
320 .plugin.compare = lyplg_type_compare_instanceid,
321 .plugin.sort = NULL,
322 .plugin.print = lyplg_type_print_node_instanceid,
323 .plugin.duplicate = lyplg_type_dup_instanceid,
324 .plugin.free = lyplg_type_free_instanceid,
325 .plugin.lyb_data_len = -1,
326 },
327 {0}
328};
libyang context handler.
LIBYANG_API_DECL LY_ERR lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len, const char **str_p)
Insert string into dictionary. If the string is already present, only a reference counter is incremen...
LIBYANG_API_DECL LY_ERR lydict_insert_zc(const struct ly_ctx *ctx, char *value, const char **str_p)
Insert string into dictionary - zerocopy version. If the string is already present,...
LY_ERR
libyang's error codes returned by the libyang functions.
Definition log.h:251
@ LYVE_DATA
Definition log.h:288
@ LY_EVALID
Definition log.h:259
@ LY_SUCCESS
Definition log.h:252
Libyang full error structure.
Definition log.h:296
const char *const char * revision
LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_format,...) _FORMAT_PRINTF(6
Create and fill error structure.
LIBYANG_API_DECL const char * lyplg_type_get_prefix(const struct lys_module *mod, LY_VALUE_FORMAT format, void *prefix_data)
Get format-specific prefix for a module.
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type, int *base, struct ly_err_item **err)
Check that the type is suitable for the parser's hints (if any) in the specified format.
LIBYANG_API_DECL LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
Implementation of lyplg_type_dup_clb for the built-in instance-identifier type.
Definition instanceid.c:336
LIBYANG_API_DECL LY_ERR lyplg_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in instance-identifier type.
Definition instanceid.c:246
LIBYANG_API_DECL void lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
Implementation of lyplg_type_free_clb for the built-in instance-identifier type.
Definition instanceid.c:359
#define LYPLG_TYPE_STORE_DYNAMIC
#define LYPLG_TYPE_STORE_IMPLEMENT
LY_DATA_TYPE basetype
uint16_t flags
Available YANG schema tree structures representing YANG module.
Compiled YANG data node.
#define LYS_IS_OUTPUT
#define LY_ARRAY_FOR(ARRAY,...)
Sized-array iterator (for-loop).
Definition tree.h:167
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition tree.h:234
#define LY_ARRAY_COUNT_TYPE
Type (i.e. size) of the sized array's size counter.
Definition tree.h:104
@ LY_VALUE_JSON
Definition tree.h:239
@ LY_VALUE_SCHEMA
Definition tree.h:236
@ LY_VALUE_CANON
Definition tree.h:235
@ LY_VALUE_XML
Definition tree.h:238
@ LY_VALUE_STR_NS
Definition tree.h:241
@ LY_VALUE_SCHEMA_RESOLVED
Definition tree.h:237
@ LY_VALUE_LYB
Definition tree.h:240
The main libyang public header.
uint8_t ly_bool
Type to indicate boolean value.
Definition log.h:35
const struct lyplg_type_record plugins_node_instanceid[]
Plugin information for instance-identifier type implementation.
API for (user) types plugins.
const struct lysc_type * realtype
Definition tree_data.h:564
const char * _canonical
Definition tree_data.h:561
YANG data representation.
Definition tree_data.h:560