libyang  2.1.30
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 (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 
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 };
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:146
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:365
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:244
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.
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:351
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:2097
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:328
libyang context handler.