libyang  5.7.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 <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  /* null the local module so that all the prefixes are printed */
63  mods = prefix_data;
64  local_mod = mods->objs[0];
65  mods->objs[0] = NULL;
66 
67  /* fallthrough */
68  case LY_VALUE_SCHEMA:
70  /* everything is prefixed */
71  inherit_prefix = 0;
72  break;
73  case LY_VALUE_CANON:
74  case LY_VALUE_JSON:
75  case LY_VALUE_LYB:
76  case LY_VALUE_STR_NS:
77  /* the same prefix is inherited and skipped */
78  inherit_prefix = 1;
79  break;
80  }
81 
82  LY_ARRAY_FOR(path, u) {
83  /* new node */
84  if (!inherit_prefix || (mod != path[u].node->module)) {
85  mod = path[u].node->module;
86  ret = ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), path[u].node->name);
87  } else {
88  ret = ly_strcat(&result, "/%s", path[u].node->name);
89  }
90  LY_CHECK_GOTO(ret, cleanup);
91 
92  /* node predicates */
93  LY_ARRAY_FOR(path[u].predicates, v) {
94  struct ly_path_predicate *pred = &path[u].predicates[v];
95 
96  switch (pred->type) {
97  case LY_PATH_PREDTYPE_POSITION:
98  /* position predicate */
99  ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
100  break;
101  case LY_PATH_PREDTYPE_LIST:
102  /* key-predicate */
103  ret = lyplg_type_print_val(pred->key, pred->value, format, prefix_data, &strval);
104  LY_CHECK_GOTO(ret, cleanup);
105 
106  /* default quote */
107  quot = '\'';
108  if (strchr(strval, quot)) {
109  quot = '"';
110  }
111  if (inherit_prefix) {
112  /* always the same prefix as the parent */
113  ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
114  } else {
115  ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
116  pred->key->name, quot, strval, quot);
117  }
118  lydict_remove(pred->key->module->ctx, strval);
119  break;
120  case LY_PATH_PREDTYPE_LEAFLIST:
121  /* leaf-list-predicate */
122  ret = lyplg_type_print_val(path[u].node, pred->value, format, prefix_data, &strval);
123  LY_CHECK_GOTO(ret, cleanup);
124 
125  /* default quote */
126  quot = '\'';
127  if (strchr(strval, quot)) {
128  quot = '"';
129  }
130  ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
131  lydict_remove(path[u].node->module->ctx, strval);
132  break;
133  case LY_PATH_PREDTYPE_LIST_VAR:
134  LOGINT(path[u].node->module->ctx);
135  ret = LY_EINT;
136  goto cleanup;
137  }
138 
139  LY_CHECK_GOTO(ret, cleanup);
140  }
141  }
142 
143 cleanup:
144  if (local_mod) {
145  mods->objs[0] = (void *)local_mod;
146  }
147  if (ret) {
148  free(result);
149  } else {
150  *str = result;
151  }
152  return ret;
153 }
154 
155 static LY_ERR
156 lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
157  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
158  struct lyd_value *storage, struct lys_glob_unres *unres, 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  ret = lyplg_type_lypath_new(ctx, value, value_size, options, (format == LY_VALUE_LYB) ? LY_VALUE_JSON : format,
181  prefix_data, ctx_node, unres, &path, err);
182  LY_CHECK_GOTO(ret, cleanup);
183 
184  /* store value */
185  storage->target = path;
186 
187  /* check status */
188  ret = lyplg_type_lypath_check_status(ctx_node, path, format, prefix_data, err);
189  LY_CHECK_GOTO(ret, cleanup);
190 
191  /* store canonical value */
192  if (format == LY_VALUE_CANON) {
193  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
194  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
195  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
196  LY_CHECK_GOTO(ret, cleanup);
197  } else {
198  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
199  LY_CHECK_GOTO(ret, cleanup);
200  }
201  } else {
202  /* JSON format with prefix is the canonical one */
203  ret = instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
204  LY_CHECK_GOTO(ret, cleanup);
205 
206  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
207  LY_CHECK_GOTO(ret, cleanup);
208  }
209 
210 cleanup:
211  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
212  free((void *)value);
213  }
214 
215  if (ret) {
216  lyplg_type_free_instanceid(ctx, storage);
217  }
218  if (!ret && type_inst->require_instance) {
219  /* needs to be resolved */
220  return LY_EINCOMPLETE;
221  } else {
222  return ret;
223  }
224 }
225 
226 static LY_ERR
227 lyplg_type_validate_tree_instanceid(const struct ly_ctx *ctx, const struct lysc_type *UNUSED(type),
228  const struct lyd_node *ctx_node, const struct lyd_node *UNUSED(tree), struct lyd_value *storage,
229  struct ly_err_item **err)
230 {
231  LY_ERR ret = LY_SUCCESS;
232  struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)storage->realtype;
233  const char *value;
234  char *path;
235 
236  /* instance-identifier must be a leaf or leaf-list */
237  assert(ctx_node);
238 
239  *err = NULL;
240 
241  if (!type_inst->require_instance) {
242  /* redundant to resolve */
243  return LY_SUCCESS;
244  }
245 
246  /* find the target in data */
247  if ((ret = ly_path_eval(storage->target, ctx_node, NULL, NULL))) {
248  value = lyd_value_get_canonical(ctx, storage);
249  path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
250  return ly_err_new(err, ret, LYVE_DATA, path, strdup("instance-required"), LY_ERRMSG_NOINST, value);
251  }
252 
253  return LY_SUCCESS;
254 }
255 
256 static const void *
257 lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
258  void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
259 {
260  char *ret;
261 
262  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
263  if (dynamic) {
264  *dynamic = 0;
265  }
266  if (value_size_bits) {
267  *value_size_bits = strlen(value->_canonical) * 8;
268  }
269  return value->_canonical;
270  }
271 
272  /* print the value in the specific format */
273  if (instanceid_path2str(value->target, format, prefix_data, &ret)) {
274  return NULL;
275  }
276 
277  *dynamic = 1;
278  if (value_size_bits) {
279  *value_size_bits = strlen(ret) * 8;
280  }
281 
282  return ret;
283 }
284 
285 static LY_ERR
286 lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
287 {
288  LY_ERR ret;
289 
290  memset(dup, 0, sizeof *dup);
291 
292  /* canonical value */
293  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
294  LY_CHECK_GOTO(ret, error);
295 
296  /* copy path */
297  ret = ly_path_dup(ctx, original->target, &dup->target);
298  LY_CHECK_GOTO(ret, error);
299 
300  dup->realtype = original->realtype;
301  return LY_SUCCESS;
302 
303 error:
304  lyplg_type_free_instanceid(ctx, dup);
305  return ret;
306 }
307 
308 LIBYANG_API_DEF void
309 lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
310 {
311  lydict_remove(ctx, value->_canonical);
312  value->_canonical = NULL;
313  ly_path_free(value->target);
314 }
315 
324  {
325  .module = "",
326  .revision = NULL,
327  .name = LY_TYPE_INST_STR,
328 
329  .plugin.id = "ly2 instance-identifier",
330  .plugin.lyb_size = lyplg_type_lyb_size_variable_bytes,
331  .plugin.store = lyplg_type_store_instanceid,
332  .plugin.validate_value = NULL,
333  .plugin.validate_tree = lyplg_type_validate_tree_instanceid,
334  .plugin.compare = lyplg_type_compare_simple,
335  .plugin.sort = lyplg_type_sort_simple,
336  .plugin.print = lyplg_type_print_instanceid,
337  .plugin.duplicate = lyplg_type_dup_instanceid,
338  .plugin.free = lyplg_type_free_instanceid,
339  },
340  {0}
341 };
struct lysc_type * realtype
Definition: tree_data.h:527
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:323
Generic structure for a data node.
Definition: tree_data.h:783
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:309
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:523
const char * _canonical
Definition: tree_data.h:524
Definition: log.h:262
Libyang full error structure.
Definition: log.h:300
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:292
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)