libyang 2.1.148
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
Loading...
Searching...
No Matches
instanceid.c
Go to the documentation of this file.
1
14#define _GNU_SOURCE /* strdup */
15
16#include "plugins_types.h"
17
18#include <stdint.h>
19#include <stdlib.h>
20
21#include "libyang.h"
22
23/* additional internal headers for some useful simple macros */
24#include "common.h"
25#include "compat.h"
26#include "path.h"
27#include "plugins_internal.h" /* LY_TYPE_*_STR */
28
47static LY_ERR
48instanceid_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, *local_mod = NULL;
54 struct ly_set *mods = NULL;
55 ly_bool inherit_prefix = 0, d;
56 const char *strval;
57
58 switch (format) {
59 case LY_VALUE_XML:
60 /* null the local module so that all the prefixes are printed */
61 mods = prefix_data;
62 local_mod = mods->objs[0];
63 mods->objs[0] = NULL;
64
65 /* fallthrough */
66 case LY_VALUE_SCHEMA:
68 /* everything is prefixed */
69 inherit_prefix = 0;
70 break;
71 case LY_VALUE_CANON:
72 case LY_VALUE_JSON:
73 case LY_VALUE_LYB:
74 case LY_VALUE_STR_NS:
75 /* the same prefix is inherited and skipped */
76 inherit_prefix = 1;
77 break;
78 }
79
80 LY_ARRAY_FOR(path, u) {
81 /* new node */
82 if (!inherit_prefix || (mod != path[u].node->module)) {
83 mod = path[u].node->module;
84 ret = ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), path[u].node->name);
85 } else {
86 ret = ly_strcat(&result, "/%s", path[u].node->name);
87 }
88 LY_CHECK_GOTO(ret, cleanup);
89
90 /* node predicates */
91 LY_ARRAY_FOR(path[u].predicates, v) {
92 struct ly_path_predicate *pred = &path[u].predicates[v];
93
94 switch (pred->type) {
95 case LY_PATH_PREDTYPE_POSITION:
96 /* position predicate */
97 ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
98 break;
99 case LY_PATH_PREDTYPE_LIST:
100 /* key-predicate */
101 strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
102 &d, NULL);
103
104 /* default quote */
105 quot = '\'';
106 if (strchr(strval, quot)) {
107 quot = '"';
108 }
109 if (inherit_prefix) {
110 /* always the same prefix as the parent */
111 ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
112 } else {
113 ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
114 pred->key->name, quot, strval, quot);
115 }
116 if (d) {
117 free((char *)strval);
118 }
119 break;
120 case LY_PATH_PREDTYPE_LEAFLIST:
121 /* leaf-list-predicate */
122 strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
123 &d, NULL);
124
125 /* default quote */
126 quot = '\'';
127 if (strchr(strval, quot)) {
128 quot = '"';
129 }
130 ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
131 if (d) {
132 free((char *)strval);
133 }
134 break;
135 case LY_PATH_PREDTYPE_LIST_VAR:
136 LOGINT(path[u].node->module->ctx);
137 ret = LY_EINT;
138 goto cleanup;
139 }
140
141 LY_CHECK_GOTO(ret, cleanup);
142 }
143 }
144
145cleanup:
146 if (local_mod) {
147 mods->objs[0] = (void *)local_mod;
148 }
149 if (ret) {
150 free(result);
151 } else {
152 *str = result;
153 }
154 return ret;
155}
156
157LIBYANG_API_DEF LY_ERR
158lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
159 uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
160 struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
161{
162 LY_ERR ret = LY_SUCCESS;
163 struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
164 struct ly_path *path;
165 char *canon;
166
167 /* init storage */
168 memset(storage, 0, sizeof *storage);
169 storage->realtype = type;
170
171 /* check hints */
172 ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
173 LY_CHECK_GOTO(ret, cleanup);
174
175 /* compile instance-identifier into path */
176 if (format == LY_VALUE_LYB) {
177 /* value in LYB format is the same as in JSON format. */
178 ret = lyplg_type_lypath_new(ctx, value, value_len, options, LY_VALUE_JSON, prefix_data, ctx_node,
179 unres, &path, err);
180 } else {
181 ret = lyplg_type_lypath_new(ctx, value, value_len, options, format, prefix_data, ctx_node,
182 unres, &path, err);
183 }
184 LY_CHECK_GOTO(ret, cleanup);
185
186 /* store value */
187 storage->target = path;
188
189 /* check status */
190 ret = lyplg_type_lypath_check_status(ctx_node, path, format, prefix_data, err);
191 LY_CHECK_GOTO(ret, cleanup);
192
193 /* store canonical value */
194 if (format == LY_VALUE_CANON) {
195 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
196 ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
197 options &= ~LYPLG_TYPE_STORE_DYNAMIC;
198 LY_CHECK_GOTO(ret, cleanup);
199 } else {
200 ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
201 LY_CHECK_GOTO(ret, cleanup);
202 }
203 } else {
204 /* JSON format with prefix is the canonical one */
205 ret = instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
206 LY_CHECK_GOTO(ret, cleanup);
207
208 ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
209 LY_CHECK_GOTO(ret, cleanup);
210 }
211
212cleanup:
213 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
214 free((void *)value);
215 }
216
217 if (ret) {
218 lyplg_type_free_instanceid(ctx, storage);
219 }
220 if (!ret && type_inst->require_instance) {
221 /* needs to be resolved */
222 return LY_EINCOMPLETE;
223 } else {
224 return ret;
225 }
226}
227
228LIBYANG_API_DEF LY_ERR
229lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *UNUSED(type),
230 const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage,
231 struct ly_err_item **err)
232{
233 LY_ERR ret = LY_SUCCESS;
234 struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)storage->realtype;
235 const char *value;
236 char *path;
237
238 *err = NULL;
239
240 if (!type_inst->require_instance) {
241 /* redundant to resolve */
242 return LY_SUCCESS;
243 }
244
245 /* find the target in data */
246 if ((ret = ly_path_eval(storage->target, tree, NULL, NULL))) {
247 value = lyplg_type_print_instanceid(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
248 path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
249 return ly_err_new(err, ret, LYVE_DATA, path, strdup("instance-required"), LY_ERRMSG_NOINST, value);
250 }
251
252 return LY_SUCCESS;
253}
254
255LIBYANG_API_DEF LY_ERR
256lyplg_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2)
257{
259
260 if (val1 == val2) {
261 return LY_SUCCESS;
262 } else if (LY_ARRAY_COUNT(val1->target) != LY_ARRAY_COUNT(val2->target)) {
263 return LY_ENOT;
264 }
265
266 LY_ARRAY_FOR(val1->target, u) {
267 struct ly_path *s1 = &val1->target[u];
268 struct ly_path *s2 = &val2->target[u];
269
270 if ((s1->node != s2->node) || (s1->predicates && (LY_ARRAY_COUNT(s1->predicates) != LY_ARRAY_COUNT(s2->predicates)))) {
271 return LY_ENOT;
272 }
273 LY_ARRAY_FOR(s1->predicates, v) {
274 struct ly_path_predicate *pred1 = &s1->predicates[v];
275 struct ly_path_predicate *pred2 = &s2->predicates[v];
276
277 if (pred1->type != pred2->type) {
278 return LY_ENOT;
279 }
280
281 switch (pred1->type) {
282 case LY_PATH_PREDTYPE_POSITION:
283 /* position predicate */
284 if (pred1->position != pred2->position) {
285 return LY_ENOT;
286 }
287 break;
288 case LY_PATH_PREDTYPE_LIST:
289 /* key-predicate */
290 if ((pred1->key != pred2->key) ||
291 ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
292 return LY_ENOT;
293 }
294 break;
295 case LY_PATH_PREDTYPE_LEAFLIST:
296 /* leaf-list predicate */
297 if (((struct lysc_node_leaflist *)s1->node)->type->plugin->compare(&pred1->value, &pred2->value)) {
298 return LY_ENOT;
299 }
300 break;
301 case LY_PATH_PREDTYPE_LIST_VAR:
302 /* key-predicate with a variable */
303 if ((pred1->key != pred2->key) || strcmp(pred1->variable, pred2->variable)) {
304 return LY_ENOT;
305 }
306 break;
307 }
308 }
309 }
310
311 return LY_SUCCESS;
312}
313
314LIBYANG_API_DEF const void *
315lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
316 void *prefix_data, ly_bool *dynamic, size_t *value_len)
317{
318 char *ret;
319
320 if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
321 if (dynamic) {
322 *dynamic = 0;
323 }
324 if (value_len) {
325 *value_len = strlen(value->_canonical);
326 }
327 return value->_canonical;
328 }
329
330 /* print the value in the specific format */
331 if (instanceid_path2str(value->target, format, prefix_data, &ret)) {
332 return NULL;
333 }
334 *dynamic = 1;
335 if (value_len) {
336 *value_len = strlen(ret);
337 }
338 return ret;
339}
340
341LIBYANG_API_DEF LY_ERR
342lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
343{
344 LY_ERR ret;
345
346 memset(dup, 0, sizeof *dup);
347
348 /* canonical value */
349 ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
350 LY_CHECK_GOTO(ret, error);
351
352 /* copy path */
353 ret = ly_path_dup(ctx, original->target, &dup->target);
354 LY_CHECK_GOTO(ret, error);
355
356 dup->realtype = original->realtype;
357 return LY_SUCCESS;
358
359error:
361 return ret;
362}
363
364LIBYANG_API_DEF void
365lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
366{
367 lydict_remove(ctx, value->_canonical);
368 value->_canonical = NULL;
369 ly_path_free(ctx, value->target);
370}
371
380 {
381 .module = "",
382 .revision = NULL,
383 .name = LY_TYPE_INST_STR,
384
385 .plugin.id = "libyang 2 - instance-identifier, version 1",
386 .plugin.store = lyplg_type_store_instanceid,
387 .plugin.validate = lyplg_type_validate_instanceid,
388 .plugin.compare = lyplg_type_compare_instanceid,
389 .plugin.sort = NULL,
390 .plugin.print = lyplg_type_print_instanceid,
391 .plugin.duplicate = lyplg_type_dup_instanceid,
392 .plugin.free = lyplg_type_free_instanceid,
393 .plugin.lyb_data_len = -1,
394 },
395 {0}
396};
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_remove(const struct ly_ctx *ctx, const char *value)
Remove specified string from the dictionary. It decrement reference counter for the string and if it ...
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:248
@ LYVE_DATA
Definition log.h:285
@ LY_ENOT
Definition log.h:262
@ LY_EINT
Definition log.h:255
@ LY_SUCCESS
Definition log.h:249
@ LY_EINCOMPLETE
Definition log.h:258
Libyang full error structure.
Definition log.h:293
Structure to hold a set of (not necessary somehow connected) objects. Usually used for lyd_node,...
Definition set.h:47
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_lypath_check_status(const struct lysc_node *ctx_node, const struct ly_path *path, LY_VALUE_FORMAT format, void *prefix_data, struct ly_err_item **err)
Check that the lypath instance-identifier value is allowed based on the status of the nodes.
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_lypath_new(const struct ly_ctx *ctx, const char *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *ctx_node, struct lys_glob_unres *unres, struct ly_path **path, struct ly_err_item **err)
Helper function to create internal schema path representation for instance-identifier value represent...
LIBYANG_API_DEF LY_ERR lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
Implementation of lyplg_type_store_clb for the built-in instance-identifier type.
Definition instanceid.c:158
LIBYANG_API_DEF 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:342
LIBYANG_API_DEF 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:256
LIBYANG_API_DEF 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:365
#define LYPLG_TYPE_STORE_DYNAMIC
LY_DATA_TYPE basetype
Available YANG schema tree structures representing YANG module.
Compiled YANG data node.
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition tree.h:148
#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
LIBYANG_API_DEF const void * lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len)
Definition instanceid.c:315
LIBYANG_API_DEF LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *UNUSED(type), const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
Definition instanceid.c:229
const struct lyplg_type_record plugins_instanceid[]
Plugin information for instance-identifier type implementation.
Definition instanceid.c:379
The main libyang public header.
uint8_t ly_bool
Type to indicate boolean value.
Definition log.h:35
API for (user) types plugins.
LIBYANG_API_DECL char * lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
Generate path of the given node in the requested format.
@ LYD_PATH_STD
Definition tree_data.h:2326
const struct lysc_type * realtype
Definition tree_data.h:564
const char * _canonical
Definition tree_data.h:561
Generic structure for a data node.
Definition tree_data.h:781
YANG data representation.
Definition tree_data.h:560