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