libyang  2.0.7
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
integer.c
Go to the documentation of this file.
1 
15 #define _GNU_SOURCE /* asprintf, strdup */
16 #include <sys/cdefs.h>
17 
18 #include "plugins_types.h"
19 
20 #include <inttypes.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include "libyang.h"
26 
27 /* additional internal headers for some useful simple macros */
28 #include "common.h"
29 #include "compat.h"
30 #include "plugins_internal.h" /* LY_TYPE_*_STR */
31 
44 static size_t integer_lyb_size[] = {
45  [LY_TYPE_INT8] = 1, [LY_TYPE_INT16] = 2, [LY_TYPE_INT32] = 4, [LY_TYPE_INT64] = 8,
47 };
48 
49 API LY_ERR
50 lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
51  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
52  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
53  struct ly_err_item **err)
54 {
55  LY_ERR ret = LY_SUCCESS;
56  int64_t num;
57  int base = 1;
58  char *canon;
59  struct lysc_type_num *type_num = (struct lysc_type_num *)type;
60 
61  /* init storage */
62  memset(storage, 0, sizeof *storage);
63  storage->realtype = type;
64 
65  if (format == LY_VALUE_LYB) {
66  /* validation */
67  if (value_len != integer_lyb_size[type->basetype]) {
68  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB signed integer value size %zu (expected %zu).",
69  value_len, integer_lyb_size[type->basetype]);
70  goto cleanup;
71  }
72 
73  /* get the integer */
74  switch (type->basetype) {
75  case LY_TYPE_INT8:
76  num = *(int8_t *)value;
77  break;
78  case LY_TYPE_INT16:
79  num = *(int16_t *)value;
80  break;
81  case LY_TYPE_INT32:
82  num = *(int32_t *)value;
83  break;
84  case LY_TYPE_INT64:
85  num = *(int64_t *)value;
86  break;
87  default:
88  LOGINT(ctx);
89  ret = LY_EINT;
90  goto cleanup;
91  }
92  } else {
93  /* check hints */
94  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, &base, err);
95  LY_CHECK_GOTO(ret, cleanup);
96 
97  /* parse the integer */
98  switch (type->basetype) {
99  case LY_TYPE_INT8:
100  ret = lyplg_type_parse_int("int8", base, INT64_C(-128), INT64_C(127), value, value_len, &num, err);
101  break;
102  case LY_TYPE_INT16:
103  ret = lyplg_type_parse_int("int16", base, INT64_C(-32768), INT64_C(32767), value, value_len, &num, err);
104  break;
105  case LY_TYPE_INT32:
106  ret = lyplg_type_parse_int("int32", base, INT64_C(-2147483648), INT64_C(2147483647), value, value_len, &num, err);
107  break;
108  case LY_TYPE_INT64:
109  ret = lyplg_type_parse_int("int64", base, INT64_C(-9223372036854775807) - INT64_C(1),
110  INT64_C(9223372036854775807), value, value_len, &num, err);
111  break;
112  default:
113  LOGINT(ctx);
114  ret = LY_EINT;
115  }
116  LY_CHECK_GOTO(ret, cleanup);
117  }
118 
119  /* set the value, matters for big-endian */
120  switch (type->basetype) {
121  case LY_TYPE_INT8:
122  storage->int8 = num;
123  break;
124  case LY_TYPE_INT16:
125  storage->int16 = num;
126  break;
127  case LY_TYPE_INT32:
128  storage->int32 = num;
129  break;
130  case LY_TYPE_INT64:
131  storage->int64 = num;
132  break;
133  default:
134  break;
135  }
136 
137  if (format == LY_VALUE_CANON) {
138  /* store canonical value */
139  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
140  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
141  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
142  LY_CHECK_GOTO(ret, cleanup);
143  } else {
144  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
145  LY_CHECK_GOTO(ret, cleanup);
146  }
147  } else {
148  /* generate canonical value */
149  LY_CHECK_ERR_GOTO(asprintf(&canon, "%" PRId64, num) == -1, ret = LY_EMEM, cleanup);
150 
151  /* store it */
152  ret = lydict_insert_zc(ctx, canon, (const char **)&storage->_canonical);
153  LY_CHECK_GOTO(ret, cleanup);
154  }
155 
156  /* validate range of the number */
157  if (type_num->range) {
158  ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical,
159  strlen(storage->_canonical), err);
160  LY_CHECK_GOTO(ret, cleanup);
161  }
162 
163 cleanup:
164  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
165  free((void *)value);
166  }
167 
168  if (ret) {
169  lyplg_type_free_simple(ctx, storage);
170  }
171  return ret;
172 }
173 
174 API LY_ERR
175 lyplg_type_compare_int(const struct lyd_value *val1, const struct lyd_value *val2)
176 {
177  if (val1->realtype != val2->realtype) {
178  return LY_ENOT;
179  }
180 
181  switch (val1->realtype->basetype) {
182  case LY_TYPE_INT8:
183  if (val1->int8 != val2->int8) {
184  return LY_ENOT;
185  }
186  break;
187  case LY_TYPE_INT16:
188  if (val1->int16 != val2->int16) {
189  return LY_ENOT;
190  }
191  break;
192  case LY_TYPE_INT32:
193  if (val1->int32 != val2->int32) {
194  return LY_ENOT;
195  }
196  break;
197  case LY_TYPE_INT64:
198  if (val1->int64 != val2->int64) {
199  return LY_ENOT;
200  }
201  break;
202  default:
203  break;
204  }
205  return LY_SUCCESS;
206 }
207 
208 API const void *
209 lyplg_type_print_int(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
210  void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
211 {
212  if (format == LY_VALUE_LYB) {
213  *dynamic = 0;
214  if (value_len) {
215  *value_len = integer_lyb_size[value->realtype->basetype];
216  }
217  switch (value->realtype->basetype) {
218  case LY_TYPE_INT8:
219  return &value->int8;
220  case LY_TYPE_INT16:
221  return &value->int16;
222  case LY_TYPE_INT32:
223  return &value->int32;
224  case LY_TYPE_INT64:
225  return &value->int64;
226  default:
227  break;
228  }
229  return NULL;
230  }
231 
232  /* use the cached canonical value */
233  if (dynamic) {
234  *dynamic = 0;
235  }
236  if (value_len) {
237  *value_len = strlen(value->_canonical);
238  }
239  return value->_canonical;
240 }
241 
242 API LY_ERR
243 lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
244  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
245  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
246  struct ly_err_item **err)
247 {
248  LY_ERR ret = LY_SUCCESS;
249  uint64_t num;
250  int base = 0;
251  char *canon;
252  struct lysc_type_num *type_num = (struct lysc_type_num *)type;
253 
254  /* init storage */
255  memset(storage, 0, sizeof *storage);
256  storage->realtype = type;
257 
258  if (format == LY_VALUE_LYB) {
259  /* validation */
260  if (value_len != integer_lyb_size[type->basetype]) {
261  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB unsigned integer value size %zu (expected %zu).",
262  value_len, integer_lyb_size[type->basetype]);
263  goto cleanup;
264  }
265 
266  /* get the integer */
267  switch (type->basetype) {
268  case LY_TYPE_UINT8:
269  num = *(uint8_t *)value;
270  break;
271  case LY_TYPE_UINT16:
272  num = *(uint16_t *)value;
273  break;
274  case LY_TYPE_UINT32:
275  num = *(uint32_t *)value;
276  break;
277  case LY_TYPE_UINT64:
278  num = *(uint64_t *)value;
279  break;
280  default:
281  LOGINT(ctx);
282  ret = LY_EINT;
283  goto cleanup;
284  }
285  } else {
286  /* check hints */
287  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, &base, err);
288  LY_CHECK_GOTO(ret, cleanup);
289 
290  /* parse the integer */
291  switch (type->basetype) {
292  case LY_TYPE_UINT8:
293  ret = lyplg_type_parse_uint("uint8", base, UINT64_C(255), value, value_len, &num, err);
294  break;
295  case LY_TYPE_UINT16:
296  ret = lyplg_type_parse_uint("uint16", base, UINT64_C(65535), value, value_len, &num, err);
297  break;
298  case LY_TYPE_UINT32:
299  ret = lyplg_type_parse_uint("uint32", base, UINT64_C(4294967295), value, value_len, &num, err);
300  break;
301  case LY_TYPE_UINT64:
302  ret = lyplg_type_parse_uint("uint64", base, UINT64_C(18446744073709551615), value, value_len, &num, err);
303  break;
304  default:
305  LOGINT(ctx);
306  ret = LY_EINT;
307  }
308  LY_CHECK_GOTO(ret, cleanup);
309  }
310 
311  /* store value, matters for big-endian */
312  switch (type->basetype) {
313  case LY_TYPE_UINT8:
314  storage->uint8 = num;
315  break;
316  case LY_TYPE_UINT16:
317  storage->uint16 = num;
318  break;
319  case LY_TYPE_UINT32:
320  storage->uint32 = num;
321  break;
322  case LY_TYPE_UINT64:
323  storage->uint64 = num;
324  break;
325  default:
326  break;
327  }
328 
329  if (format == LY_VALUE_CANON) {
330  /* store canonical value */
331  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
332  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
333  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
334  LY_CHECK_GOTO(ret, cleanup);
335  } else {
336  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
337  LY_CHECK_GOTO(ret, cleanup);
338  }
339  } else {
340  /* generate canonical value */
341  LY_CHECK_ERR_GOTO(asprintf(&canon, "%" PRIu64, num) == -1, ret = LY_EMEM, cleanup);
342 
343  /* store it */
344  ret = lydict_insert_zc(ctx, canon, (const char **)&storage->_canonical);
345  LY_CHECK_GOTO(ret, cleanup);
346  }
347 
348  /* validate range of the number */
349  if (type_num->range) {
350  ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical,
351  strlen(storage->_canonical), err);
352  LY_CHECK_GOTO(ret, cleanup);
353  }
354 
355 cleanup:
356  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
357  free((void *)value);
358  }
359 
360  if (ret) {
361  lyplg_type_free_simple(ctx, storage);
362  }
363  return ret;
364 }
365 
366 API LY_ERR
367 lyplg_type_compare_uint(const struct lyd_value *val1, const struct lyd_value *val2)
368 {
369  if (val1->realtype != val2->realtype) {
370  return LY_ENOT;
371  }
372 
373  switch (val1->realtype->basetype) {
374  case LY_TYPE_UINT8:
375  if (val1->uint8 != val2->uint8) {
376  return LY_ENOT;
377  }
378  break;
379  case LY_TYPE_UINT16:
380  if (val1->uint16 != val2->uint16) {
381  return LY_ENOT;
382  }
383  break;
384  case LY_TYPE_UINT32:
385  if (val1->uint32 != val2->uint32) {
386  return LY_ENOT;
387  }
388  break;
389  case LY_TYPE_UINT64:
390  if (val1->uint64 != val2->uint64) {
391  return LY_ENOT;
392  }
393  break;
394  default:
395  break;
396  }
397  return LY_SUCCESS;
398 }
399 
400 API const void *
401 lyplg_type_print_uint(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
402  void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
403 {
404  if (format == LY_VALUE_LYB) {
405  *dynamic = 0;
406  if (value_len) {
407  *value_len = integer_lyb_size[value->realtype->basetype];
408  }
409  switch (value->realtype->basetype) {
410  case LY_TYPE_UINT8:
411  return &value->uint8;
412  case LY_TYPE_UINT16:
413  return &value->uint16;
414  case LY_TYPE_UINT32:
415  return &value->uint32;
416  case LY_TYPE_UINT64:
417  return &value->uint64;
418  default:
419  break;
420  }
421  return NULL;
422  }
423 
424  /* use the cached canonical value */
425  if (dynamic) {
426  *dynamic = 0;
427  }
428  if (value_len) {
429  *value_len = strlen(value->_canonical);
430  }
431  return value->_canonical;
432 }
433 
441 const struct lyplg_type_record plugins_integer[] = {
442  {
443  .module = "",
444  .revision = NULL,
445  .name = LY_TYPE_UINT8_STR,
446 
447  .plugin.id = "libyang 2 - integers, version 1",
448  .plugin.store = lyplg_type_store_uint,
449  .plugin.validate = NULL,
450  .plugin.compare = lyplg_type_compare_uint,
451  .plugin.sort = NULL,
452  .plugin.print = lyplg_type_print_uint,
453  .plugin.duplicate = lyplg_type_dup_simple,
454  .plugin.free = lyplg_type_free_simple
455  }, {
456  .module = "",
457  .revision = NULL,
458  .name = LY_TYPE_UINT16_STR,
459 
460  .plugin.id = "libyang 2 - integers, version 1",
461  .plugin.store = lyplg_type_store_uint,
462  .plugin.validate = NULL,
463  .plugin.compare = lyplg_type_compare_uint,
464  .plugin.sort = NULL,
465  .plugin.print = lyplg_type_print_uint,
466  .plugin.duplicate = lyplg_type_dup_simple,
467  .plugin.free = lyplg_type_free_simple
468  }, {
469  .module = "",
470  .revision = NULL,
471  .name = LY_TYPE_UINT32_STR,
472 
473  .plugin.id = "libyang 2 - integers, version 1",
474  .plugin.store = lyplg_type_store_uint,
475  .plugin.validate = NULL,
476  .plugin.compare = lyplg_type_compare_uint,
477  .plugin.sort = NULL,
478  .plugin.print = lyplg_type_print_uint,
479  .plugin.duplicate = lyplg_type_dup_simple,
480  .plugin.free = lyplg_type_free_simple
481  }, {
482  .module = "",
483  .revision = NULL,
484  .name = LY_TYPE_UINT64_STR,
485 
486  .plugin.id = "libyang 2 - integers, version 1",
487  .plugin.store = lyplg_type_store_uint,
488  .plugin.validate = NULL,
489  .plugin.compare = lyplg_type_compare_uint,
490  .plugin.sort = NULL,
491  .plugin.print = lyplg_type_print_uint,
492  .plugin.duplicate = lyplg_type_dup_simple,
493  .plugin.free = lyplg_type_free_simple
494  }, {
495  .module = "",
496  .revision = NULL,
497  .name = LY_TYPE_INT8_STR,
498 
499  .plugin.id = "libyang 2 - integers, version 1",
500  .plugin.store = lyplg_type_store_int,
501  .plugin.validate = NULL,
502  .plugin.compare = lyplg_type_compare_int,
503  .plugin.sort = NULL,
504  .plugin.print = lyplg_type_print_int,
505  .plugin.duplicate = lyplg_type_dup_simple,
506  .plugin.free = lyplg_type_free_simple
507  }, {
508  .module = "",
509  .revision = NULL,
510  .name = LY_TYPE_INT16_STR,
511 
512  .plugin.id = "libyang 2 - integers, version 1",
513  .plugin.store = lyplg_type_store_int,
514  .plugin.validate = NULL,
515  .plugin.compare = lyplg_type_compare_int,
516  .plugin.sort = NULL,
517  .plugin.print = lyplg_type_print_int,
518  .plugin.duplicate = lyplg_type_dup_simple,
519  .plugin.free = lyplg_type_free_simple
520  }, {
521  .module = "",
522  .revision = NULL,
523  .name = LY_TYPE_INT32_STR,
524 
525  .plugin.id = "libyang 2 - integers, version 1",
526  .plugin.store = lyplg_type_store_int,
527  .plugin.validate = NULL,
528  .plugin.compare = lyplg_type_compare_int,
529  .plugin.sort = NULL,
530  .plugin.print = lyplg_type_print_int,
531  .plugin.duplicate = lyplg_type_dup_simple,
532  .plugin.free = lyplg_type_free_simple
533  }, {
534  .module = "",
535  .revision = NULL,
536  .name = LY_TYPE_INT64_STR,
537 
538  .plugin.id = "libyang 2 - integers, version 1",
539  .plugin.store = lyplg_type_store_int,
540  .plugin.validate = NULL,
541  .plugin.compare = lyplg_type_compare_int,
542  .plugin.sort = NULL,
543  .plugin.print = lyplg_type_print_int,
544  .plugin.duplicate = lyplg_type_dup_simple,
545  .plugin.free = lyplg_type_free_simple
546  },
547  {0}
548 };
libyang context handler.
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,...
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...
LY_ERR
libyang's error codes returned by the libyang functions.
Definition: log.h:242
@ LYVE_DATA
Definition: log.h:279
@ LY_EMEM
Definition: log.h:244
@ LY_ENOT
Definition: log.h:256
@ LY_EVALID
Definition: log.h:250
@ LY_EINT
Definition: log.h:249
@ LY_SUCCESS
Definition: log.h:243
Libyang full error structure.
Definition: log.h:287
const char * module
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's hints (if any) in the specified format.
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.
LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_msg,...)
Create and fill error structure.
LY_ERR lyplg_type_parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value, size_t value_len, int64_t *ret, struct ly_err_item **err)
Unsigned integer value parser and validator.
LY_ERR lyplg_type_parse_uint(const char *datatype, int base, uint64_t max, const char *value, size_t value_len, uint64_t *ret, struct ly_err_item **err)
Unsigned integer value parser and validator.
API LY_ERR lyplg_type_compare_int(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in signed integer types.
Definition: integer.c:175
API LY_ERR lyplg_type_compare_uint(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in unsigned integer types.
Definition: integer.c:367
LY_ERR lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
Implementation of lyplg_type_dup_clb for a generic simple type.
void lyplg_type_free_simple(const struct ly_ctx *ctx, struct lyd_value *value)
Implementation of lyplg_type_free_clb for a generic simple type.
#define LYPLG_TYPE_STORE_DYNAMIC
struct lysc_range * range
Definition: tree_schema.h:1540
LY_DATA_TYPE basetype
Definition: tree_schema.h:1531
Compiled YANG data node.
Definition: tree_schema.h:1644
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:235
@ LY_TYPE_UINT16
Definition: tree.h:207
@ LY_TYPE_INT16
Definition: tree.h:221
@ LY_TYPE_INT32
Definition: tree.h:222
@ LY_TYPE_UINT8
Definition: tree.h:206
@ LY_TYPE_INT64
Definition: tree.h:223
@ LY_TYPE_INT8
Definition: tree.h:220
@ LY_TYPE_UINT64
Definition: tree.h:209
@ LY_TYPE_UINT32
Definition: tree.h:208
@ LY_VALUE_CANON
Definition: tree.h:236
@ LY_VALUE_LYB
Definition: tree.h:241
API const void * lyplg_type_print_uint(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
Definition: integer.c:401
const struct lyplg_type_record plugins_integer[]
Plugin information for integer types implementation.
Definition: integer.c:441
API const void * lyplg_type_print_int(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
Definition: integer.c:209
API LY_ERR lyplg_type_store_int(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 *UNUSED(prefix_data), uint32_t hints, const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
Definition: integer.c:50
API LY_ERR lyplg_type_store_uint(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 *UNUSED(prefix_data), uint32_t hints, const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
Definition: integer.c:243
The main libyang public header.
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:25
API for (user) types plugins.
const struct lysc_type * realtype
Definition: tree_data.h:535
const char * _canonical
Definition: tree_data.h:532
YANG data representation.
Definition: tree_data.h:531