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
xpath1.0.c
Go to the documentation of this file.
1 
15 #include "plugins_types.h"
16 
17 #include <stdint.h>
18 #include <stdlib.h>
19 
20 #include "libyang.h"
21 
22 #include "common.h"
23 #include "compat.h"
24 
25 /* internal header */
26 #include "xpath.h"
27 
41  struct lyxp_expr *exp;
42  const struct ly_ctx *ctx;
43  void *prefix_data;
45 };
46 
63 static LY_ERR
64 xpath10_print_token(const char *token, uint16_t tok_len, ly_bool is_nametest, const struct lys_module **context_mod,
65  const struct ly_ctx *resolve_ctx, LY_VALUE_FORMAT resolve_format, const void *resolve_prefix_data,
66  LY_VALUE_FORMAT get_format, void *get_prefix_data, char **token_p, struct ly_err_item **err)
67 {
68  LY_ERR ret = LY_SUCCESS;
69  const char *str_begin, *str_next, *prefix;
70  ly_bool is_prefix, has_prefix = 0;
71  char *str = NULL;
72  void *mem;
73  uint32_t len, str_len = 0, pref_len;
74  const struct lys_module *mod;
75 
76  str_begin = token;
77 
78  while (!(ret = ly_value_prefix_next(str_begin, token + tok_len, &len, &is_prefix, &str_next)) && len) {
79  if (!is_prefix) {
80  if (!has_prefix && is_nametest && (get_format == LY_VALUE_XML) && *context_mod) {
81  /* prefix is always needed, get it in the target format */
82  prefix = lyplg_type_get_prefix(*context_mod, get_format, get_prefix_data);
83  if (!prefix) {
84  ret = ly_err_new(err, LY_EINT, LYVE_DATA, NULL, NULL, "Internal error.");
85  goto cleanup;
86  }
87 
88  /* append the nametest and prefix */
89  mem = realloc(str, str_len + strlen(prefix) + 1 + len + 1);
90  LY_CHECK_ERR_GOTO(!mem, ret = ly_err_new(err, LY_EMEM, LYVE_DATA, NULL, NULL, "No memory."), cleanup);
91  str = mem;
92  str_len += sprintf(str + str_len, "%s:%.*s", prefix, len, str_begin);
93  } else {
94  /* just append the string, we may get the first expression node without a prefix but since this
95  * is not strictly forbidden, allow it */
96  mem = realloc(str, str_len + len + 1);
97  LY_CHECK_ERR_GOTO(!mem, ret = ly_err_new(err, LY_EMEM, LYVE_DATA, NULL, NULL, "No memory."), cleanup);
98  str = mem;
99  str_len += sprintf(str + str_len, "%.*s", len, str_begin);
100  }
101  } else {
102  /* remember there was a prefix found */
103  has_prefix = 1;
104 
105  /* resolve the module in the original format */
106  mod = lyplg_type_identity_module(resolve_ctx, NULL, str_begin, len, resolve_format, resolve_prefix_data);
107  if (!mod && is_nametest) {
108  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Failed to resolve prefix \"%.*s\".", len, str_begin);
109  goto cleanup;
110  }
111 
112  if (is_nametest && ((get_format == LY_VALUE_JSON) || (get_format == LY_VALUE_LYB)) && (*context_mod == mod)) {
113  /* inherit the prefix and do not print it again */
114  } else {
115  if (mod) {
116  /* get the prefix in the target format */
117  prefix = lyplg_type_get_prefix(mod, get_format, get_prefix_data);
118  if (!prefix) {
119  ret = ly_err_new(err, LY_EINT, LYVE_DATA, NULL, NULL, "Internal error.");
120  goto cleanup;
121  }
122  pref_len = strlen(prefix);
123  } else {
124  /* invalid prefix, just copy it */
125  prefix = str_begin;
126  pref_len = len;
127  }
128 
129  /* append the prefix */
130  mem = realloc(str, str_len + pref_len + 2);
131  LY_CHECK_ERR_GOTO(!mem, ret = ly_err_new(err, LY_EMEM, LYVE_DATA, NULL, NULL, "No memory."), cleanup);
132  str = mem;
133  str_len += sprintf(str + str_len, "%.*s:", (int)pref_len, prefix);
134  }
135 
136  if (is_nametest) {
137  /* update context module */
138  *context_mod = mod;
139  }
140  }
141 
142  str_begin = str_next;
143  }
144 
145 cleanup:
146  if (ret) {
147  free(str);
148  } else {
149  *token_p = str;
150  }
151  return ret;
152 }
153 
169 static LY_ERR
170 xpath10_print_subexpr_r(uint16_t *cur_idx, enum lyxp_token end_tok, const struct lys_module *context_mod,
171  const struct lyd_value_xpath10 *xp_val, LY_VALUE_FORMAT format, void *prefix_data, char **str_value,
172  uint32_t *str_len, struct ly_err_item **err)
173 {
174  enum lyxp_token cur_tok, sub_end_tok;
175  char *str_tok;
176  void *mem;
177  const char *cur_exp_ptr;
178  ly_bool is_nt;
179  const struct lys_module *orig_context_mod = context_mod;
180 
181  while (*cur_idx < xp_val->exp->used) {
182  cur_tok = xp_val->exp->tokens[*cur_idx];
183  cur_exp_ptr = xp_val->exp->expr + xp_val->exp->tok_pos[*cur_idx];
184 
185  if ((cur_tok == LYXP_TOKEN_NAMETEST) || (cur_tok == LYXP_TOKEN_LITERAL)) {
186  /* tokens that may include prefixes, get them in the target format */
187  is_nt = (cur_tok == LYXP_TOKEN_NAMETEST) ? 1 : 0;
188  LY_CHECK_RET(xpath10_print_token(cur_exp_ptr, xp_val->exp->tok_len[*cur_idx], is_nt, &context_mod,
189  xp_val->ctx, xp_val->format, xp_val->prefix_data, format, prefix_data, &str_tok, err));
190 
191  /* append the converted token */
192  mem = realloc(*str_value, *str_len + strlen(str_tok) + 1);
193  LY_CHECK_ERR_GOTO(!mem, free(str_tok), error_mem);
194  *str_value = mem;
195  *str_len += sprintf(*str_value + *str_len, "%s", str_tok);
196  free(str_tok);
197 
198  /* token processed */
199  ++(*cur_idx);
200  } else {
201  if ((cur_tok == LYXP_TOKEN_OPER_LOG) || (cur_tok == LYXP_TOKEN_OPER_UNI) || (cur_tok == LYXP_TOKEN_OPER_MATH)) {
202  /* copy the token with spaces around */
203  mem = realloc(*str_value, *str_len + 1 + xp_val->exp->tok_len[*cur_idx] + 2);
204  LY_CHECK_GOTO(!mem, error_mem);
205  *str_value = mem;
206  *str_len += sprintf(*str_value + *str_len, " %.*s ", (int)xp_val->exp->tok_len[*cur_idx], cur_exp_ptr);
207 
208  /* reset context mod */
209  context_mod = orig_context_mod;
210  } else {
211  /* just copy the token */
212  mem = realloc(*str_value, *str_len + xp_val->exp->tok_len[*cur_idx] + 1);
213  LY_CHECK_GOTO(!mem, error_mem);
214  *str_value = mem;
215  *str_len += sprintf(*str_value + *str_len, "%.*s", (int)xp_val->exp->tok_len[*cur_idx], cur_exp_ptr);
216  }
217 
218  /* token processed but keep it in cur_tok */
219  ++(*cur_idx);
220 
221  if (end_tok && (cur_tok == end_tok)) {
222  /* end token found */
223  break;
224  } else if ((cur_tok == LYXP_TOKEN_BRACK1) || (cur_tok == LYXP_TOKEN_PAR1)) {
225  sub_end_tok = (cur_tok == LYXP_TOKEN_BRACK1) ? LYXP_TOKEN_BRACK2 : LYXP_TOKEN_PAR2;
226 
227  /* parse the subexpression separately, use the current context mod */
228  LY_CHECK_RET(xpath10_print_subexpr_r(cur_idx, sub_end_tok, context_mod, xp_val, format, prefix_data,
229  str_value, str_len, err));
230  }
231  }
232  }
233 
234  return LY_SUCCESS;
235 
236 error_mem:
237  return ly_err_new(err, LY_EMEM, LYVE_DATA, NULL, NULL, "No memory.");
238 }
239 
250 static LY_ERR
251 xpath10_print_value(const struct lyd_value_xpath10 *xp_val, LY_VALUE_FORMAT format, void *prefix_data,
252  char **str_value, struct ly_err_item **err)
253 {
254  LY_ERR ret = LY_SUCCESS;
255  uint16_t expr_idx = 0;
256  uint32_t str_len = 0;
257 
258  *str_value = NULL;
259 
260  /* recursively print the expression */
261  ret = xpath10_print_subexpr_r(&expr_idx, 0, NULL, xp_val, format, prefix_data, str_value, &str_len, err);
262 
263  if (ret) {
264  free(*str_value);
265  }
266  return ret;
267 }
268 
269 API LY_ERR
270 lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
271  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
272  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
273  struct ly_err_item **err)
274 {
275  LY_ERR ret = LY_SUCCESS;
276  struct lysc_type_str *type_str = (struct lysc_type_str *)type;
277  struct lyd_value_xpath10 *val;
278  char *canon;
279 
280  /* init storage */
281  memset(storage, 0, sizeof *storage);
282  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
283  LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);
284  storage->realtype = type;
285 
286  /* check hints */
287  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
288  LY_CHECK_GOTO(ret, cleanup);
289 
290  /* length restriction of the string */
291  if (type_str->length) {
292  /* value_len is in bytes, but we need number of characters here */
293  ret = lyplg_type_validate_range(LY_TYPE_STRING, type_str->length, ly_utf8len(value, value_len), value, value_len, err);
294  LY_CHECK_GOTO(ret, cleanup);
295  }
296 
297  /* pattern restrictions */
298  ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err);
299  LY_CHECK_GOTO(ret, cleanup);
300 
301  /* store format-specific data and context for later prefix resolution */
302  ret = lyplg_type_prefix_data_new(ctx, value, value_len, format, prefix_data, &val->format, &val->prefix_data);
303  LY_CHECK_GOTO(ret, cleanup);
304  val->ctx = ctx;
305 
306  /* parse */
307  ret = lyxp_expr_parse(ctx, value, value_len, 1, &val->exp);
308  LY_CHECK_GOTO(ret, cleanup);
309 
310  /* store canonical value */
311  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
312  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
313  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
314  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
315  LY_CHECK_GOTO(ret, cleanup);
316  } else {
317  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
318  LY_CHECK_GOTO(ret, cleanup);
319  }
320  } else {
321  /* JSON format with prefix is the canonical one */
322  ret = xpath10_print_value(val, LY_VALUE_JSON, NULL, &canon, err);
323  LY_CHECK_GOTO(ret, cleanup);
324 
325  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
326  LY_CHECK_GOTO(ret, cleanup);
327  }
328 
329 cleanup:
330  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
331  free((void *)value);
332  }
333 
334  if (ret) {
335  lyplg_type_free_xpath10(ctx, storage);
336  }
337  return ret;
338 }
339 
340 API const void *
341 lyplg_type_print_xpath10(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
342  void *prefix_data, ly_bool *dynamic, size_t *value_len)
343 {
344  struct lyd_value_xpath10 *val;
345  char *ret;
346  struct ly_err_item *err = NULL;
347 
348  LYD_VALUE_GET(value, val);
349 
350  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
351  /* canonical */
352  if (dynamic) {
353  *dynamic = 0;
354  }
355  if (value_len) {
356  *value_len = strlen(value->_canonical);
357  }
358  return value->_canonical;
359  }
360 
361  /* print in the specific format */
362  if (xpath10_print_value(val, format, prefix_data, &ret, &err)) {
363  if (err) {
364  LOGVAL_ERRITEM(ctx, err);
365  ly_err_free(err);
366  }
367  return NULL;
368  }
369 
370  *dynamic = 1;
371  if (value_len) {
372  *value_len = strlen(ret);
373  }
374  return ret;
375 }
376 
377 API LY_ERR
378 lyplg_type_dup_xpath10(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
379 {
380  LY_ERR ret = LY_SUCCESS;
381  struct lyd_value_xpath10 *orig_val, *dup_val;
382 
383  /* init dup value */
384  memset(dup, 0, sizeof *dup);
385  dup->realtype = original->realtype;
386 
387  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
388  LY_CHECK_GOTO(ret, cleanup);
389 
390  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val);
391  LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
392  dup_val->ctx = ctx;
393 
394  LYD_VALUE_GET(original, orig_val);
395  ret = lyxp_expr_dup(ctx, orig_val->exp, &dup_val->exp);
396  LY_CHECK_GOTO(ret, cleanup);
397 
398  ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
399  LY_CHECK_GOTO(ret, cleanup);
400  dup_val->format = orig_val->format;
401 
402 cleanup:
403  if (ret) {
404  lyplg_type_free_xpath10(ctx, dup);
405  }
406  return ret;
407 }
408 
409 API void
410 lyplg_type_free_xpath10(const struct ly_ctx *ctx, struct lyd_value *value)
411 {
412  struct lyd_value_xpath10 *val;
413 
414  lydict_remove(ctx, value->_canonical);
415  value->_canonical = NULL;
416  LYD_VALUE_GET(value, val);
417  if (val) {
418  lyxp_expr_free(ctx, val->exp);
420 
422  }
423 }
424 
433  {
434  .module = "ietf-yang-types",
435  .revision = "2013-07-15",
436  .name = "xpath1.0",
437 
438  .plugin.id = "libyang 2 - xpath1.0, version 1",
439  .plugin.store = lyplg_type_store_xpath10,
440  .plugin.validate = NULL,
441  .plugin.compare = lyplg_type_compare_simple,
442  .plugin.sort = NULL,
443  .plugin.print = lyplg_type_print_xpath10,
444  .plugin.duplicate = lyplg_type_dup_xpath10,
445  .plugin.free = lyplg_type_free_xpath10,
446  .plugin.lyb_data_len = -1,
447  },
448  {0}
449 };
LY_ERR lyplg_type_dup_xpath10(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
Implementation of lyplg_type_dup_clb for the ietf-yang-types xpath1.0 type.
Definition: xpath1.0.c:378
struct lysc_type * realtype
Definition: tree_data.h:539
Compiled YANG data node.
Definition: tree_schema.h:1666
struct ly_ctx * ctx
Definition: tree_schema.h:2343
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.
LY_ERR lyplg_type_store_xpath10(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 ietf-yang-types xpath1.0 type.
Definition: log.h:248
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 ...
#define LYPLG_TYPE_STORE_DYNAMIC
LY_ERR void ly_err_free(void *ptr)
Destructor for the error records created with ly_err_new().
LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig, void **dup)
Duplicate prefix data.
#define LOGMEM(CTX)
Definition: tree_edit.h:22
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...
Definition: log.h:253
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.
struct lysc_pattern ** patterns
Definition: tree_schema.h:1580
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.
struct lysc_range * length
Definition: tree_schema.h:1579
YANG data representation.
Definition: tree_data.h:535
const char * _canonical
Definition: tree_data.h:536
const void * lyplg_type_print_xpath10(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 ietf-yang-types xpath1.0 type.
Definition: xpath1.0.c:341
Libyang full error structure.
Definition: log.h:291
Definition: log.h:283
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:578
LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, size_t value_len, LY_VALUE_FORMAT format, const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Store used prefixes in a string into an internal libyang structure used in lyd_value.
struct lyplg_type_record plugins_xpath10[]
Plugin information for xpath1.0 type implementation.
Definition: xpath1.0.c:432
Definition: log.h:254
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.
struct lyxp_expr * exp
Definition: xpath1.0.c:41
void lyplg_type_free_xpath10(const struct ly_ctx *ctx, struct lyd_value *value)
Implementation of lyplg_type_free_clb for the ietf-yang-types xpath1.0 type.
Definition: xpath1.0.c:410
LY_VALUE_FORMAT format
Definition: xpath1.0.c:44
struct ly_ctx * ctx
Definition: xpath1.0.c:42
Available YANG schema tree structures representing YANG module.
Definition: tree_schema.h:2342
Stored value structure for xpath1.0.
Definition: xpath1.0.c:40
const char * module
void * prefix_data
Definition: xpath1.0.c:43
LY_ERR lyplg_type_compare_simple(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for a generic simple type.
#define LYPLG_TYPE_VAL_INLINE_DESTROY(type_val)
Destroy a prepared value.
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:235
void lyplg_type_prefix_data_free(LY_VALUE_FORMAT format, void *prefix_data)
Free internal prefix data.
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
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
LY_ERR lyplg_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len, struct ly_err_item **err)
Data type validator for pattern-restricted string values.
struct lys_module * lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data)
Get the corresponding module for the identity value.
LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval, size_t strval_len, struct ly_err_item **err)
Data type validator for a range/length-restricted values.
API for (user) types plugins.
libyang context handler.