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
enumeration.c
Go to the documentation of this file.
1 
16 #define _GNU_SOURCE /* strdup */
17 
18 #include "plugins_types.h"
19 
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "libyang.h"
25 
26 /* additional internal headers for some useful simple macros */
27 #include "compat.h"
28 #include "ly_common.h"
29 #include "plugins_internal.h" /* LY_TYPE_*_STR */
30 
40 #define ENUM_FIXED_SIZE_BITS(type) \
41  lyplg_type_get_highest_set_bit_pos(\
42  ((struct lysc_type_enum *)type)->enums[LY_ARRAY_COUNT(((struct lysc_type_enum *)type)->enums) - 1].value)
43 
44 static void
45 lyplg_type_lyb_size_enum(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint32_t *fixed_size_bits)
46 {
47  const struct lysc_type_enum *type_enum = (struct lysc_type_enum *)type;
48  uint32_t max_value;
49 
50  *size_type = LYPLG_LYB_SIZE_FIXED_BITS;
51 
52  if (type_enum->enums[0].value < 0) {
53  /* we need the full 4 bytes */
54  *fixed_size_bits = 32;
55  return;
56  }
57 
58  /* value of the last enum, sorted */
59  max_value = type_enum->enums[LY_ARRAY_COUNT(type_enum->enums) - 1].value;
60 
61  /* learn the position of the highest set bit, the least amount of bits that can hold the number */
62  *fixed_size_bits = lyplg_type_get_highest_set_bit_pos(max_value);
63 }
64 
65 static LY_ERR
66 lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint32_t value_size_bits,
67  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
68  const struct lysc_node *UNUSED(ctx_node), const struct lysc_ext_instance *UNUSED(top_ext),
69  struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
70 {
71  struct lysc_type_enum *type_enum = (struct lysc_type_enum *)type;
72  LY_ERR ret = LY_SUCCESS;
74  ly_bool found = 0;
75  uint32_t value_size;
76  int64_t num = 0;
77  int32_t num_val;
78 
79  /* init storage */
80  memset(storage, 0, sizeof *storage);
81  storage->realtype = type;
82 
83  /* check value length */
84  ret = lyplg_type_check_value_size("enumeration", format, value_size_bits, LYPLG_LYB_SIZE_FIXED_BITS,
85  ENUM_FIXED_SIZE_BITS(type), &value_size, err);
86  LY_CHECK_GOTO(ret, cleanup);
87 
88  if (format == LY_VALUE_LYB) {
89  /* convert the value to host byte order */
90  memcpy(&num, value, value_size);
91  num = le64toh(num);
92  num_val = num;
93 
94  /* find the matching enumeration value item */
95  LY_ARRAY_FOR(type_enum->enums, u) {
96  if (type_enum->enums[u].value == num_val) {
97  found = 1;
98  break;
99  }
100  }
101 
102  if (!found) {
103  /* value not found */
104  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid enumeration value % " PRIi32 ".", num_val);
105  goto cleanup;
106  }
107 
108  /* store value */
109  storage->enum_item = &type_enum->enums[u];
110 
111  /* canonical settings via dictionary due to free callback */
112  ret = lydict_insert(ctx, type_enum->enums[u].name, 0, &storage->_canonical);
113  LY_CHECK_GOTO(ret, cleanup);
114 
115  /* success */
116  goto cleanup;
117  }
118 
119  /* check hints */
120  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
121  LY_CHECK_GOTO(ret, cleanup);
122 
123  /* find the matching enumeration value item */
124  LY_ARRAY_FOR(type_enum->enums, u) {
125  if (!ly_strncmp(type_enum->enums[u].name, value, value_size)) {
126  found = 1;
127  break;
128  }
129  }
130 
131  if (!found) {
132  /* enum not found */
133  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid enumeration value \"%.*s\".", (int)value_size,
134  (char *)value);
135  goto cleanup;
136  }
137 
138  /* store value */
139  storage->enum_item = &type_enum->enums[u];
140 
141  /* store canonical value, it always is */
142  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
143  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
144  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
145  LY_CHECK_GOTO(ret, cleanup);
146  } else {
147  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
148  LY_CHECK_GOTO(ret, cleanup);
149  }
150 
151 cleanup:
152  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
153  free((void *)value);
154  }
155 
156  if (ret) {
157  lyplg_type_free_simple(ctx, storage);
158  }
159  return ret;
160 }
161 
162 static int
163 lyplg_type_sort_enum(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
164  const struct lyd_value *val2)
165 {
166  if (val1->enum_item->value > val2->enum_item->value) {
167  return -1;
168  } else if (val1->enum_item->value < val2->enum_item->value) {
169  return 1;
170  } else {
171  return 0;
172  }
173 }
174 
175 static const void *
176 lyplg_type_print_enum(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
177  void *UNUSED(prefix_data), ly_bool *dynamic, uint32_t *value_size_bits)
178 {
179  int64_t prev_num = 0, num = 0;
180  void *buf;
181 
182  if (format == LY_VALUE_LYB) {
183  prev_num = num = value->enum_item->value;
184  num = htole64(num);
185  if (num == prev_num) {
186  /* values are equal, little-endian */
187  *dynamic = 0;
188  if (value_size_bits) {
189  *value_size_bits = ENUM_FIXED_SIZE_BITS(value->realtype);
190  }
191  return &value->enum_item->value;
192  } else {
193  /* values differ, big-endian */
194  buf = calloc(1, 4);
195  LY_CHECK_RET(!buf, NULL);
196 
197  *dynamic = 1;
198  if (value_size_bits) {
199  *value_size_bits = ENUM_FIXED_SIZE_BITS(value->realtype);
200  }
201  memcpy(buf, &num, 4);
202  return buf;
203  }
204  }
205 
206  /* use the cached canonical value */
207  if (dynamic) {
208  *dynamic = 0;
209  }
210  if (value_size_bits) {
211  *value_size_bits = strlen(value->_canonical) * 8;
212  }
213  return value->_canonical;
214 }
215 
224  {
225  .module = "",
226  .revision = NULL,
227  .name = LY_TYPE_ENUM_STR,
228 
229  .plugin.id = "ly2 enumeration",
230  .plugin.lyb_size = lyplg_type_lyb_size_enum,
231  .plugin.store = lyplg_type_store_enum,
232  .plugin.validate_value = NULL,
233  .plugin.validate_tree = NULL,
234  .plugin.compare = lyplg_type_compare_simple,
235  .plugin.sort = lyplg_type_sort_enum,
236  .plugin.print = lyplg_type_print_enum,
237  .plugin.duplicate = lyplg_type_dup_simple,
238  .plugin.free = lyplg_type_free_simple,
239  },
240  {0}
241 };
struct lysc_type * realtype
Definition: tree_data.h:567
Compiled YANG data node.
Definition: tree_schema.h:1434
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
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.
lyplg_lyb_size_type
Type of the LYB size of a value of a particular type.
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
#define LYPLG_TYPE_STORE_DYNAMIC
#define ENUM_FIXED_SIZE_BITS(type)
Definition: enumeration.c:40
struct lyplg_type_record plugins_enumeration[]
Plugin information for enumeration type implementation.
Definition: enumeration.c:223
The main libyang public header.
YANG data representation.
Definition: tree_data.h:563
const char * _canonical
Definition: tree_data.h:564
Libyang full error structure.
Definition: log.h:285
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.
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...
Definition: log.h:248
const char * module
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
#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.
LIBYANG_API_DECL uint64_t lyplg_type_get_highest_set_bit_pos(uint64_t num)
Learn the position of the highest set bit in a number. Represents also the least amount of bits requi...
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:234
struct lysc_type_bitenum_item * enums
Definition: tree_schema.h:1358
LY_DATA_TYPE basetype
Definition: tree_schema.h:1300
LIBYANG_API_DECL 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.
LIBYANG_API_DECL 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.
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.