libyang  2.0.194
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
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 
47 static LY_ERR
48 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  switch (format) {
58  case LY_VALUE_XML:
59  case LY_VALUE_SCHEMA:
61  /* everything is prefixed */
62  inherit_prefix = 0;
63  break;
64  case LY_VALUE_CANON:
65  case LY_VALUE_JSON:
66  case LY_VALUE_LYB:
67  case LY_VALUE_STR_NS:
68  /* the same prefix is inherited and skipped */
69  inherit_prefix = 1;
70  break;
71  }
72 
73  LY_ARRAY_FOR(path, u) {
74  /* new node */
75  if (!inherit_prefix || (mod != path[u].node->module)) {
76  mod = path[u].node->module;
77  ret = ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), path[u].node->name);
78  } else {
79  ret = ly_strcat(&result, "/%s", path[u].node->name);
80  }
81  LY_CHECK_GOTO(ret, cleanup);
82 
83  /* node predicates */
84  LY_ARRAY_FOR(path[u].predicates, v) {
85  struct ly_path_predicate *pred = &path[u].predicates[v];
86 
87  switch (path[u].pred_type) {
88  case LY_PATH_PREDTYPE_NONE:
89  break;
90  case LY_PATH_PREDTYPE_POSITION:
91  /* position predicate */
92  ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
93  break;
94  case LY_PATH_PREDTYPE_LIST:
95  /* key-predicate */
96  strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
97  &d, NULL);
98 
99  /* default quote */
100  quot = '\'';
101  if (strchr(strval, quot)) {
102  quot = '"';
103  }
104  if (inherit_prefix) {
105  /* always the same prefix as the parent */
106  ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
107  } else {
108  ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
109  pred->key->name, quot, strval, quot);
110  }
111  if (d) {
112  free((char *)strval);
113  }
114  break;
115  case LY_PATH_PREDTYPE_LEAFLIST:
116  /* leaf-list-predicate */
117  strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
118  &d, NULL);
119 
120  /* default quote */
121  quot = '\'';
122  if (strchr(strval, quot)) {
123  quot = '"';
124  }
125  ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
126  if (d) {
127  free((char *)strval);
128  }
129  break;
130  }
131 
132  LY_CHECK_GOTO(ret, cleanup);
133  }
134  }
135 
136 cleanup:
137  if (ret) {
138  free(result);
139  } else {
140  *str = result;
141  }
142  return ret;
143 }
144 
145 LIBYANG_API_DEF LY_ERR
146 lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
147  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
148  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
149 {
150  LY_ERR ret = LY_SUCCESS;
151  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
152  struct ly_path *path;
153  char *canon;
154 
155  /* init storage */
156  memset(storage, 0, sizeof *storage);
157  storage->realtype = type;
158 
159  /* check hints */
160  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
161  LY_CHECK_GOTO(ret, cleanup);
162 
163  /* compile instance-identifier into path */
164  if (format == LY_VALUE_LYB) {
165  /* The @p value in LYB format is the same as in JSON format. */
166  ret = lyplg_type_lypath_new(ctx, value, value_len, options, LY_VALUE_JSON, prefix_data, ctx_node,
167  unres, &path, err);
168  } else {
169  ret = lyplg_type_lypath_new(ctx, value, value_len, options, format, prefix_data, ctx_node,
170  unres, &path, err);
171  }
172  LY_CHECK_GOTO(ret, cleanup);
173 
174  /* store value */
175  storage->target = path;
176 
177  /* check status */
178  ret = lyplg_type_lypath_check_status(ctx_node, path, format, prefix_data, err);
179  LY_CHECK_GOTO(ret, cleanup);
180 
181  /* store canonical value */
182  if (format == LY_VALUE_CANON) {
183  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
184  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
185  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
186  LY_CHECK_GOTO(ret, cleanup);
187  } else {
188  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
189  LY_CHECK_GOTO(ret, cleanup);
190  }
191  } else {
192  /* JSON format with prefix is the canonical one */
193  ret = instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
194  LY_CHECK_GOTO(ret, cleanup);
195 
196  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
197  LY_CHECK_GOTO(ret, cleanup);
198  }
199 
200 cleanup:
201  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
202  free((void *)value);
203  }
204 
205  if (ret) {
206  lyplg_type_free_instanceid(ctx, storage);
207  }
208  if (!ret && type_inst->require_instance) {
209  /* needs to be resolved */
210  return LY_EINCOMPLETE;
211  } else {
212  return ret;
213  }
214 }
215 
216 LIBYANG_API_DEF LY_ERR
217 lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *UNUSED(type),
218  const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage,
219  struct ly_err_item **err)
220 {
221  LY_ERR ret = LY_SUCCESS;
222  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)storage->realtype;
223  const char *value;
224  char *path;
225 
226  *err = NULL;
227 
228  if (!type_inst->require_instance) {
229  /* redundant to resolve */
230  return LY_SUCCESS;
231  }
232 
233  /* find the target in data */
234  if ((ret = ly_path_eval(storage->target, tree, NULL))) {
235  value = lyplg_type_print_instanceid(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
236  path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
237  return ly_err_new(err, ret, LYVE_DATA, path, strdup("instance-required"), LY_ERRMSG_NOINST, value);
238  }
239 
240  return LY_SUCCESS;
241 }
242 
243 LIBYANG_API_DEF LY_ERR
244 lyplg_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2)
245 {
246  LY_ARRAY_COUNT_TYPE u, v;
247 
248  if (val1->realtype != val2->realtype) {
249  return LY_ENOT;
250  }
251 
252  if (val1 == val2) {
253  return LY_SUCCESS;
254  } else if (LY_ARRAY_COUNT(val1->target) != LY_ARRAY_COUNT(val2->target)) {
255  return LY_ENOT;
256  }
257 
258  LY_ARRAY_FOR(val1->target, u) {
259  struct ly_path *s1 = &val1->target[u];
260  struct ly_path *s2 = &val2->target[u];
261 
262  if ((s1->node != s2->node) || (s1->pred_type != s2->pred_type) ||
263  (s1->predicates && (LY_ARRAY_COUNT(s1->predicates) != LY_ARRAY_COUNT(s2->predicates)))) {
264  return LY_ENOT;
265  }
266  if (s1->predicates) {
267  LY_ARRAY_FOR(s1->predicates, v) {
268  struct ly_path_predicate *pred1 = &s1->predicates[v];
269  struct ly_path_predicate *pred2 = &s2->predicates[v];
270 
271  switch (s1->pred_type) {
272  case LY_PATH_PREDTYPE_NONE:
273  break;
274  case LY_PATH_PREDTYPE_POSITION:
275  /* position predicate */
276  if (pred1->position != pred2->position) {
277  return LY_ENOT;
278  }
279  break;
280  case LY_PATH_PREDTYPE_LIST:
281  /* key-predicate */
282  if ((pred1->key != pred2->key) ||
283  ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
284  return LY_ENOT;
285  }
286  break;
287  case LY_PATH_PREDTYPE_LEAFLIST:
288  /* leaf-list predicate */
289  if (((struct lysc_node_leaflist *)s1->node)->type->plugin->compare(&pred1->value, &pred2->value)) {
290  return LY_ENOT;
291  }
292  }
293  }
294  }
295  }
296 
297  return LY_SUCCESS;
298 }
299 
300 LIBYANG_API_DEF const void *
301 lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
302  void *prefix_data, ly_bool *dynamic, size_t *value_len)
303 {
304  char *ret;
305 
306  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
307  if (dynamic) {
308  *dynamic = 0;
309  }
310  if (value_len) {
311  *value_len = strlen(value->_canonical);
312  }
313  return value->_canonical;
314  }
315 
316  /* print the value in the specific format */
317  if (instanceid_path2str(value->target, format, prefix_data, &ret)) {
318  return NULL;
319  }
320  *dynamic = 1;
321  if (value_len) {
322  *value_len = strlen(ret);
323  }
324  return ret;
325 }
326 
327 LIBYANG_API_DEF LY_ERR
328 lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
329 {
330  LY_ERR ret;
331 
332  memset(dup, 0, sizeof *dup);
333 
334  /* canonical value */
335  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
336  LY_CHECK_GOTO(ret, error);
337 
338  /* copy path */
339  ret = ly_path_dup(ctx, original->target, &dup->target);
340  LY_CHECK_GOTO(ret, error);
341 
342  dup->realtype = original->realtype;
343  return LY_SUCCESS;
344 
345 error:
346  lyplg_type_free_instanceid(ctx, dup);
347  return ret;
348 }
349 
350 LIBYANG_API_DEF void
351 lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
352 {
353  lydict_remove(ctx, value->_canonical);
354  value->_canonical = NULL;
355  ly_path_free(ctx, value->target);
356 }
357 
365 const struct lyplg_type_record plugins_instanceid[] = {
366  {
367  .module = "",
368  .revision = NULL,
369  .name = LY_TYPE_INST_STR,
370 
371  .plugin.id = "libyang 2 - instance-identifier, version 1",
372  .plugin.store = lyplg_type_store_instanceid,
373  .plugin.validate = lyplg_type_validate_instanceid,
374  .plugin.compare = lyplg_type_compare_instanceid,
375  .plugin.sort = NULL,
376  .plugin.print = lyplg_type_print_instanceid,
377  .plugin.duplicate = lyplg_type_dup_instanceid,
378  .plugin.free = lyplg_type_free_instanceid,
379  .plugin.lyb_data_len = -1,
380  },
381  {0}
382 };
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:244
@ LYVE_DATA
Definition: log.h:281
@ LY_ENOT
Definition: log.h:258
@ LY_SUCCESS
Definition: log.h:245
@ LY_EINCOMPLETE
Definition: log.h:254
Libyang full error structure.
Definition: log.h:289
const char * module
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:146
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:328
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:244
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:351
#define LYPLG_TYPE_STORE_DYNAMIC
LY_DATA_TYPE basetype
Definition: tree_schema.h:1536
Available YANG schema tree structures representing YANG module.
Definition: tree_schema.h:2341
Compiled YANG data node.
Definition: tree_schema.h:1650
#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:235
#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:240
@ LY_VALUE_SCHEMA
Definition: tree.h:237
@ LY_VALUE_CANON
Definition: tree.h:236
@ LY_VALUE_XML
Definition: tree.h:239
@ LY_VALUE_STR_NS
Definition: tree.h:242
@ LY_VALUE_SCHEMA_RESOLVED
Definition: tree.h:238
@ LY_VALUE_LYB
Definition: tree.h:241
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:301
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:217
const struct lyplg_type_record plugins_instanceid[]
Plugin information for instance-identifier type implementation.
Definition: instanceid.c:365
The main libyang public header.
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:27
API for (user) types plugins.
@ LYD_PATH_STD
Definition: tree_data.h:2315
const struct lysc_type * realtype
Definition: tree_data.h:564
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.
const char * _canonical
Definition: tree_data.h:561
Generic structure for a data node.
Definition: tree_data.h:798
YANG data representation.
Definition: tree_data.h:560