libyang  2.1.80
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 (pred->type) {
88  case LY_PATH_PREDTYPE_POSITION:
89  /* position predicate */
90  ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
91  break;
92  case LY_PATH_PREDTYPE_LIST:
93  /* key-predicate */
94  strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
95  &d, NULL);
96 
97  /* default quote */
98  quot = '\'';
99  if (strchr(strval, quot)) {
100  quot = '"';
101  }
102  if (inherit_prefix) {
103  /* always the same prefix as the parent */
104  ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
105  } else {
106  ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
107  pred->key->name, quot, strval, quot);
108  }
109  if (d) {
110  free((char *)strval);
111  }
112  break;
113  case LY_PATH_PREDTYPE_LEAFLIST:
114  /* leaf-list-predicate */
115  strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
116  &d, NULL);
117 
118  /* default quote */
119  quot = '\'';
120  if (strchr(strval, quot)) {
121  quot = '"';
122  }
123  ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
124  if (d) {
125  free((char *)strval);
126  }
127  break;
128  case LY_PATH_PREDTYPE_LIST_VAR:
129  LOGINT(path[u].node->module->ctx);
130  ret = LY_EINT;
131  goto cleanup;
132  }
133 
134  LY_CHECK_GOTO(ret, cleanup);
135  }
136  }
137 
138 cleanup:
139  if (ret) {
140  free(result);
141  } else {
142  *str = result;
143  }
144  return ret;
145 }
146 
147 LIBYANG_API_DEF LY_ERR
148 lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
149  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
150  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
151 {
152  LY_ERR ret = LY_SUCCESS;
153  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
154  struct ly_path *path;
155  char *canon;
156 
157  /* init storage */
158  memset(storage, 0, sizeof *storage);
159  storage->realtype = type;
160 
161  /* check hints */
162  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
163  LY_CHECK_GOTO(ret, cleanup);
164 
165  /* compile instance-identifier into path */
166  if (format == LY_VALUE_LYB) {
167  /* value in LYB format is the same as in JSON format. */
168  ret = lyplg_type_lypath_new(ctx, value, value_len, options, LY_VALUE_JSON, prefix_data, ctx_node,
169  unres, &path, err);
170  } else {
171  ret = lyplg_type_lypath_new(ctx, value, value_len, options, format, prefix_data, ctx_node,
172  unres, &path, err);
173  }
174  LY_CHECK_GOTO(ret, cleanup);
175 
176  /* store value */
177  storage->target = path;
178 
179  /* check status */
180  ret = lyplg_type_lypath_check_status(ctx_node, path, format, prefix_data, err);
181  LY_CHECK_GOTO(ret, cleanup);
182 
183  /* store canonical value */
184  if (format == LY_VALUE_CANON) {
185  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
186  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
187  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
188  LY_CHECK_GOTO(ret, cleanup);
189  } else {
190  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
191  LY_CHECK_GOTO(ret, cleanup);
192  }
193  } else {
194  /* JSON format with prefix is the canonical one */
195  ret = instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
196  LY_CHECK_GOTO(ret, cleanup);
197 
198  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
199  LY_CHECK_GOTO(ret, cleanup);
200  }
201 
202 cleanup:
203  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
204  free((void *)value);
205  }
206 
207  if (ret) {
208  lyplg_type_free_instanceid(ctx, storage);
209  }
210  if (!ret && type_inst->require_instance) {
211  /* needs to be resolved */
212  return LY_EINCOMPLETE;
213  } else {
214  return ret;
215  }
216 }
217 
218 LIBYANG_API_DEF LY_ERR
219 lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *UNUSED(type),
220  const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage,
221  struct ly_err_item **err)
222 {
223  LY_ERR ret = LY_SUCCESS;
224  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)storage->realtype;
225  const char *value;
226  char *path;
227 
228  *err = NULL;
229 
230  if (!type_inst->require_instance) {
231  /* redundant to resolve */
232  return LY_SUCCESS;
233  }
234 
235  /* find the target in data */
236  if ((ret = ly_path_eval(storage->target, tree, NULL, NULL))) {
237  value = lyplg_type_print_instanceid(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
238  path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
239  return ly_err_new(err, ret, LYVE_DATA, path, strdup("instance-required"), LY_ERRMSG_NOINST, value);
240  }
241 
242  return LY_SUCCESS;
243 }
244 
245 LIBYANG_API_DEF LY_ERR
246 lyplg_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2)
247 {
248  LY_ARRAY_COUNT_TYPE u, v;
249 
250  if (val1->realtype != val2->realtype) {
251  return LY_ENOT;
252  }
253 
254  if (val1 == val2) {
255  return LY_SUCCESS;
256  } else if (LY_ARRAY_COUNT(val1->target) != LY_ARRAY_COUNT(val2->target)) {
257  return LY_ENOT;
258  }
259 
260  LY_ARRAY_FOR(val1->target, u) {
261  struct ly_path *s1 = &val1->target[u];
262  struct ly_path *s2 = &val2->target[u];
263 
264  if ((s1->node != s2->node) || (s1->predicates && (LY_ARRAY_COUNT(s1->predicates) != LY_ARRAY_COUNT(s2->predicates)))) {
265  return LY_ENOT;
266  }
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  if (pred1->type != pred2->type) {
272  return LY_ENOT;
273  }
274 
275  switch (pred1->type) {
276  case LY_PATH_PREDTYPE_POSITION:
277  /* position predicate */
278  if (pred1->position != pred2->position) {
279  return LY_ENOT;
280  }
281  break;
282  case LY_PATH_PREDTYPE_LIST:
283  /* key-predicate */
284  if ((pred1->key != pred2->key) ||
285  ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
286  return LY_ENOT;
287  }
288  break;
289  case LY_PATH_PREDTYPE_LEAFLIST:
290  /* leaf-list predicate */
291  if (((struct lysc_node_leaflist *)s1->node)->type->plugin->compare(&pred1->value, &pred2->value)) {
292  return LY_ENOT;
293  }
294  break;
295  case LY_PATH_PREDTYPE_LIST_VAR:
296  /* key-predicate with a variable */
297  if ((pred1->key != pred2->key) || strcmp(pred1->variable, pred2->variable)) {
298  return LY_ENOT;
299  }
300  break;
301  }
302  }
303  }
304 
305  return LY_SUCCESS;
306 }
307 
308 LIBYANG_API_DEF const void *
309 lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
310  void *prefix_data, ly_bool *dynamic, size_t *value_len)
311 {
312  char *ret;
313 
314  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
315  if (dynamic) {
316  *dynamic = 0;
317  }
318  if (value_len) {
319  *value_len = strlen(value->_canonical);
320  }
321  return value->_canonical;
322  }
323 
324  /* print the value in the specific format */
325  if (instanceid_path2str(value->target, format, prefix_data, &ret)) {
326  return NULL;
327  }
328  *dynamic = 1;
329  if (value_len) {
330  *value_len = strlen(ret);
331  }
332  return ret;
333 }
334 
335 LIBYANG_API_DEF LY_ERR
336 lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
337 {
338  LY_ERR ret;
339 
340  memset(dup, 0, sizeof *dup);
341 
342  /* canonical value */
343  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
344  LY_CHECK_GOTO(ret, error);
345 
346  /* copy path */
347  ret = ly_path_dup(ctx, original->target, &dup->target);
348  LY_CHECK_GOTO(ret, error);
349 
350  dup->realtype = original->realtype;
351  return LY_SUCCESS;
352 
353 error:
354  lyplg_type_free_instanceid(ctx, dup);
355  return ret;
356 }
357 
358 LIBYANG_API_DEF void
359 lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
360 {
361  lydict_remove(ctx, value->_canonical);
362  value->_canonical = NULL;
363  ly_path_free(ctx, value->target);
364 }
365 
374  {
375  .module = "",
376  .revision = NULL,
377  .name = LY_TYPE_INST_STR,
378 
379  .plugin.id = "libyang 2 - instance-identifier, version 1",
380  .plugin.store = lyplg_type_store_instanceid,
381  .plugin.validate = lyplg_type_validate_instanceid,
382  .plugin.compare = lyplg_type_compare_instanceid,
383  .plugin.sort = NULL,
384  .plugin.print = lyplg_type_print_instanceid,
385  .plugin.duplicate = lyplg_type_dup_instanceid,
386  .plugin.free = lyplg_type_free_instanceid,
387  .plugin.lyb_data_len = -1,
388  },
389  {0}
390 };
struct lysc_type * realtype
Definition: tree_data.h:564
LIBYANG_API_DECL 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:148
Compiled YANG data node.
Definition: tree_schema.h:1414
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...
struct lyplg_type_record plugins_instanceid[]
Plugin information for instance-identifier type implementation.
Definition: instanceid.c:373
Generic structure for a data node.
Definition: tree_data.h:781
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.
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:28
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...
#define LYPLG_TYPE_STORE_DYNAMIC
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 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.
Definition: log.h:261
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.
The main libyang public header.
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
YANG data representation.
Definition: tree_data.h:560
const char * _canonical
Definition: tree_data.h:561
Libyang full error structure.
Definition: log.h:299
Definition: log.h:291
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(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...
Available YANG schema tree structures representing YANG module.
Definition: tree_schema.h:2100
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&#39;s hints (if any) in the specified format.
const char * module
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
LIBYANG_API_DECL LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
Implementation of lyplg_type_validate_clb for the built-in instance-identifier type.
#define LY_ARRAY_FOR(ARRAY,...)
Sized-array iterator (for-loop).
Definition: tree.h:167
#define LY_ARRAY_COUNT_TYPE
Type (i.e. size) of the sized array&#39;s size counter.
Definition: tree.h:104
Definition: log.h:268
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, only a reference counter is incremented and no memory allocation is performed. This insert function variant avoids duplication of specified value - it is inserted into the dictionary directly.
LIBYANG_API_DECL const void * lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len)
Implementation of lyplg_type_print_clb for the built-in instance-identifier type. ...
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:234
LY_DATA_TYPE basetype
Definition: tree_schema.h:1299
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:254
API for (user) types plugins.
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 context handler.