libyang  6.1.8
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 
15 #define _GNU_SOURCE /* strdup */
16 
17 #include "plugins_types.h"
18 
19 #include <assert.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 
23 #include "libyang.h"
24 
25 /* additional internal headers for some useful simple macros */
26 #include "compat.h"
27 #include "ly_common.h"
28 #include "path.h"
29 #include "plugins_internal.h" /* LY_TYPE_*_STR */
30 
49 static LY_ERR
50 instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, void *prefix_data, char **str)
51 {
52  LY_ERR ret = LY_SUCCESS;
54  char *result = NULL, quot;
55  const struct lys_module *mod = NULL, *local_mod = NULL;
56  struct ly_set *mods = NULL;
57  ly_bool inherit_prefix = 0;
58  const char *strval;
59 
60  switch (format) {
61  case LY_VALUE_XML:
62  case LY_VALUE_STR_NS:
63  /* zero the local module so that all the prefixes are printed */
64  mods = prefix_data;
65  local_mod = mods->objs[0];
66  mods->objs[0] = NULL;
67  break;
68  case LY_VALUE_SCHEMA:
70  /* nothing to do */
71  break;
72  case LY_VALUE_CANON:
73  case LY_VALUE_CBOR:
74  case LY_VALUE_JSON:
75  case LY_VALUE_LYB:
76  /* zero the local module so that the first node is always prefixed */
77  prefix_data = NULL;
78  break;
79  }
80 
81  switch (format) {
82  case LY_VALUE_XML:
83  case LY_VALUE_SCHEMA:
85  /* everything is prefixed */
86  inherit_prefix = 0;
87  break;
88  case LY_VALUE_CANON:
89  case LY_VALUE_CBOR:
90  case LY_VALUE_JSON:
91  case LY_VALUE_LYB:
92  case LY_VALUE_STR_NS:
93  /* the same prefix is inherited and skipped */
94  inherit_prefix = 1;
95  break;
96  }
97 
98  LY_ARRAY_FOR(path, u) {
99  /* new node */
100  if (!inherit_prefix || (mod != path[u].node->module)) {
101  mod = path[u].node->module;
102  ret = ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), path[u].node->name);
103  } else {
104  ret = ly_strcat(&result, "/%s", path[u].node->name);
105  }
106  LY_CHECK_GOTO(ret, cleanup);
107 
108  /* node predicates */
109  LY_ARRAY_FOR(path[u].predicates, v) {
110  struct ly_path_predicate *pred = &path[u].predicates[v];
111 
112  switch (pred->type) {
113  case LY_PATH_PREDTYPE_POSITION:
114  /* position predicate */
115  ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
116  break;
117  case LY_PATH_PREDTYPE_LIST:
118  /* key-predicate */
119  ret = lyplg_type_print_val(pred->key, pred->value, format, prefix_data, &strval);
120  LY_CHECK_GOTO(ret, cleanup);
121 
122  /* default quote */
123  LY_CHECK_GOTO(ret = ly_val_get_quot(pred->key->module->ctx, strval, &quot), cleanup);
124  if (inherit_prefix) {
125  /* always the same prefix as the parent */
126  ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
127  } else {
128  ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
129  pred->key->name, quot, strval, quot);
130  }
131  lydict_remove(pred->key->module->ctx, strval);
132  break;
133  case LY_PATH_PREDTYPE_LEAFLIST:
134  /* leaf-list-predicate */
135  ret = lyplg_type_print_val(path[u].node, pred->value, format, prefix_data, &strval);
136  LY_CHECK_GOTO(ret, cleanup);
137 
138  /* default quote */
139  LY_CHECK_GOTO(ret = ly_val_get_quot(path[u].node->module->ctx, strval, &quot), cleanup);
140  ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
141  lydict_remove(path[u].node->module->ctx, strval);
142  break;
143  case LY_PATH_PREDTYPE_LIST_VAR:
144  LOGINT(path[u].node->module->ctx);
145  ret = LY_EINT;
146  goto cleanup;
147  }
148 
149  LY_CHECK_GOTO(ret, cleanup);
150  }
151  }
152 
153 cleanup:
154  if (local_mod) {
155  mods->objs[0] = (void *)local_mod;
156  }
157  if (ret) {
158  free(result);
159  } else {
160  *str = result;
161  }
162  return ret;
163 }
164 
165 static LY_ERR
166 lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
167  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
168  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
169 {
170  LY_ERR ret = LY_SUCCESS;
171  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
172  uint32_t value_size;
173  struct ly_path *path;
174  char *canon;
175 
176  /* init storage */
177  memset(storage, 0, sizeof *storage);
178  storage->realtype = type;
179 
180  /* check value length */
181  ret = lyplg_type_check_value_size("instance-identifier", format, value_size_bits, LYPLG_LYB_SIZE_VARIABLE_BYTES, 0,
182  &value_size, err);
183  LY_CHECK_GOTO(ret, cleanup);
184 
185  /* check hints */
186  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
187  LY_CHECK_GOTO(ret, cleanup);
188 
189  /* compile instance-identifier into path */
190  ret = lyplg_type_lypath_new(ctx, value, value_size, options, (format == LY_VALUE_LYB) ? LY_VALUE_JSON : format,
191  prefix_data, ctx_node, unres, &path, err);
192  LY_CHECK_GOTO(ret, cleanup);
193 
194  /* store value */
195  storage->target = path;
196 
197  /* check status */
198  ret = lyplg_type_lypath_check_status(ctx_node, path, format, prefix_data, err);
199  LY_CHECK_GOTO(ret, cleanup);
200 
201  /* store canonical value */
202  if (format == LY_VALUE_CANON) {
203  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
204  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
205  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
206  LY_CHECK_GOTO(ret, cleanup);
207  } else {
208  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
209  LY_CHECK_GOTO(ret, cleanup);
210  }
211  } else {
212  /* JSON format with prefix is the canonical one */
213  ret = instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
214  LY_CHECK_GOTO(ret, cleanup);
215 
216  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
217  LY_CHECK_GOTO(ret, cleanup);
218  }
219 
220 cleanup:
221  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
222  free((void *)value);
223  }
224 
225  if (ret) {
226  lyplg_type_free_instanceid(ctx, storage);
227  }
228  if (!ret && type_inst->require_instance) {
229  /* needs to be resolved */
230  return LY_EINCOMPLETE;
231  } else {
232  return ret;
233  }
234 }
235 
236 static LY_ERR
237 lyplg_type_validate_tree_instanceid(const struct ly_ctx *ctx, const struct lysc_type *UNUSED(type),
238  const struct lyd_node *ctx_node, const struct lyd_node *UNUSED(tree), struct lyd_value *storage,
239  struct ly_err_item **err)
240 {
241  LY_ERR ret = LY_SUCCESS;
242  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)storage->realtype;
243  const char *value;
244  char *path;
245 
246  /* instance-identifier must be a leaf or leaf-list */
247  assert(ctx_node);
248 
249  *err = NULL;
250 
251  if (!type_inst->require_instance) {
252  /* redundant to resolve */
253  return LY_SUCCESS;
254  }
255 
256  /* find the target in data */
257  if ((ret = ly_path_eval(storage->target, ctx_node, NULL, NULL))) {
258  value = lyd_value_get_canonical(ctx, storage);
259  path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
260  return ly_err_new(err, ret, LYVE_DATA, path, strdup("instance-required"), LY_ERRMSG_NOINST, value);
261  }
262 
263  return LY_SUCCESS;
264 }
265 
266 static const void *
267 lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
268  void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
269 {
270  char *ret;
271 
272  switch (format) {
273  case LY_VALUE_CANON:
274  case LY_VALUE_JSON:
275  case LY_VALUE_LYB:
276  case LY_VALUE_CBOR:
277  if (dynamic) {
278  *dynamic = 0;
279  }
280  if (value_size_bits) {
281  *value_size_bits = strlen(value->_canonical) * 8;
282  }
283  return value->_canonical;
284  default:
285  break;
286  }
287 
288  /* print the value in the specific format */
289  if (instanceid_path2str(value->target, format, prefix_data, &ret)) {
290  return NULL;
291  }
292 
293  *dynamic = 1;
294  if (value_size_bits) {
295  *value_size_bits = strlen(ret) * 8;
296  }
297 
298  return ret;
299 }
300 
301 static LY_ERR
302 lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
303 {
304  LY_ERR ret;
305 
306  memset(dup, 0, sizeof *dup);
307 
308  /* canonical value */
309  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
310  LY_CHECK_GOTO(ret, error);
311 
312  /* copy path */
313  ret = ly_path_dup(ctx, original->target, &dup->target);
314  LY_CHECK_GOTO(ret, error);
315 
316  dup->realtype = original->realtype;
317  return LY_SUCCESS;
318 
319 error:
320  lyplg_type_free_instanceid(ctx, dup);
321  return ret;
322 }
323 
324 LIBYANG_API_DEF void
325 lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
326 {
327  lydict_remove(ctx, value->_canonical);
328  value->_canonical = NULL;
329  ly_path_free(value->target);
330 }
331 
340  {
341  .module = "",
342  .revision = NULL,
343  .name = LY_TYPE_INST_STR,
344 
345  .plugin.id = "ly2 instance-identifier",
346  .plugin.lyb_size = lyplg_type_lyb_size_variable_bytes,
347  .plugin.store = lyplg_type_store_instanceid,
348  .plugin.validate_value = NULL,
349  .plugin.validate_tree = lyplg_type_validate_tree_instanceid,
350  .plugin.compare = lyplg_type_compare_simple,
351  .plugin.sort = lyplg_type_sort_simple,
352  .plugin.print = lyplg_type_print_instanceid,
353  .plugin.duplicate = lyplg_type_dup_instanceid,
354  .plugin.free = lyplg_type_free_instanceid,
355  },
356  {0}
357 };
struct lysc_type * realtype
Definition: tree_data.h:552
Compiled YANG data node.
Definition: tree_schema.h:1430
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
LIBYANG_API_DECL LY_ERR lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, uint32_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:339
Generic structure for a data node.
Definition: tree_data.h:815
LIBYANG_API_DECL void lyplg_type_lyb_size_variable_bytes(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint64_t *fixed_size_bits)
Implementation of lyplg_type_lyb_size_clb for a type with variable length rounded to bytes...
LIBYANG_API_DECL LY_ERR lyplg_type_compare_simple(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for a generic simple type.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:255
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:29
LIBYANG_API_DECL LY_ERR lyplg_type_check_value_size(const char *type_name, LY_VALUE_FORMAT format, uint64_t value_size_bits, enum lyplg_lyb_size_type lyb_size_type, uint64_t lyb_fixed_size_bits, uint32_t *value_size, struct ly_err_item **err)
Check a value type in bits is correct and as expected.
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 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_DEF int lyplg_type_sort_simple(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_sort_clb for a generic simple type.
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:325
LIBYANG_API_DECL LY_ERR lyplg_type_print_val(const struct lysc_node *node, const char *canon, LY_VALUE_FORMAT format, void *prefix_data, const char **value)
Convert canonical value into a value in a specific 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.
YANG data representation.
Definition: tree_data.h:548
const char * _canonical
Definition: tree_data.h:549
Definition: log.h:262
Libyang full error structure.
Definition: log.h:301
LIBYANG_API_DECL const char * lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Get the (canonical) value of a lyd_value.
Definition: log.h:293
LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *data_path, char *apptag, const char *err_format,...) _FORMAT_PRINTF(6
Create and fill error structure.
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 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:2264
const char * module
#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
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.
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:1296
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, uint32_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.
API for (user) types plugins.
libyang context handler.
assert(!value->_canonical)