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