libyang  6.3.1
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 "compat.h"
25 #include "dict.h"
26 #include "ly_array.h"
27 #include "ly_common.h"
28 #include "plugins_internal.h"
29 
39 static void
40 lyplg_type_lyb_size_enum(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint64_t *fixed_size_bits)
41 {
42  const struct lysc_type_enum *type_enum = (struct lysc_type_enum *)type;
43  LYA_COUNT_T u;
44  uint32_t max_value = 0;
45 
46  if (size_type) {
47  *size_type = LYPLG_LYB_SIZE_FIXED_BITS;
48  }
49 
50  /* learn the max value of enums */
51  LYA_FOR(type_enum->enums, u) {
52  if (type_enum->enums[u].value < 0) {
53  /* we need the full 4 bytes */
54  *fixed_size_bits = 32;
55  return;
56  }
57 
58  if ((unsigned)type_enum->enums[u].value > max_value) {
59  max_value = type_enum->enums[u].value;
60  }
61  }
62 
63  /* learn the position of the highest set bit, the least amount of bits that can hold the number */
64  *fixed_size_bits = lyplg_type_get_highest_set_bit_pos(max_value);
65 }
66 
67 static LY_ERR
68 lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
69  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
70  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
71  struct ly_err_item **err)
72 {
73  struct lysc_type_enum *type_enum = (struct lysc_type_enum *)type;
74  LY_ERR ret = LY_SUCCESS;
75  LYA_COUNT_T u;
76  uint64_t fixed_size_bits;
77  ly_bool found = 0;
78  uint32_t value_size;
79  int64_t num = 0;
80  int32_t num_val;
81 
82  /* init storage */
83  memset(storage, 0, sizeof *storage);
84  storage->realtype = type;
85 
86  /* check value length */
87  lyplg_type_lyb_size_enum(type, NULL, &fixed_size_bits);
88  ret = lyplg_type_check_value_size("enumeration", format, value_size_bits, LYPLG_LYB_SIZE_FIXED_BITS,
89  fixed_size_bits, &value_size, err);
90  LY_CHECK_GOTO(ret, cleanup);
91 
92  if (format == LY_VALUE_LYB) {
93  /* convert the value to host byte order */
94  memcpy(&num, value, value_size);
95  num = le64toh(num);
96  num_val = num;
97 
98  /* find the matching enumeration value item */
99  LYA_FOR(type_enum->enums, u) {
100  if (type_enum->enums[u].value == num_val) {
101  found = 1;
102  break;
103  }
104  }
105 
106  if (!found) {
107  /* value not found */
108  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid enumeration value % " PRIi32 ".", num_val);
109  goto cleanup;
110  }
111 
112  /* store value */
113  storage->enum_item = &type_enum->enums[u];
114 
115  /* canonical settings via dictionary due to free callback */
116  ret = lydict_insert(ctx, type_enum->enums[u].name, 0, &storage->_canonical);
117  LY_CHECK_GOTO(ret, cleanup);
118 
119  /* success */
120  goto cleanup;
121  }
122 
123  /* check hints */
124  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
125  LY_CHECK_GOTO(ret, cleanup);
126 
127  /* find the matching enumeration value item */
128  LYA_FOR(type_enum->enums, u) {
129  if (!ly_strncmp(type_enum->enums[u].name, value, value_size)) {
130  found = 1;
131  break;
132  }
133  }
134 
135  if (!found) {
136  /* enum not found */
137  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid enumeration value \"%.*s\".", (int)value_size,
138  (char *)value);
139  goto cleanup;
140  }
141 
142  /* store value */
143  storage->enum_item = &type_enum->enums[u];
144 
145  /* store canonical value, it always is */
146  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
147  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
148  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
149  LY_CHECK_GOTO(ret, cleanup);
150  } else {
151  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
152  LY_CHECK_GOTO(ret, cleanup);
153  }
154 
155 cleanup:
156  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
157  free((void *)value);
158  }
159 
160  if (ret) {
161  lyplg_type_free_simple(ctx, storage);
162  }
163  return ret;
164 }
165 
166 static int
167 lyplg_type_sort_enum(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
168  const struct lyd_value *val2)
169 {
170  if (val1->enum_item->value < val2->enum_item->value) {
171  return -1;
172  } else if (val1->enum_item->value > val2->enum_item->value) {
173  return 1;
174  } else {
175  return 0;
176  }
177 }
178 
179 static const void *
180 lyplg_type_print_enum(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
181  void *UNUSED(prefix_data), ly_bool *dynamic, uint64_t *value_size_bits)
182 {
183  uint64_t fixed_size_bits;
184  int64_t prev_num = 0, num = 0;
185  void *buf;
186 
187  if (format == LY_VALUE_LYB) {
188  lyplg_type_lyb_size_enum(value->realtype, NULL, &fixed_size_bits);
189 
190  prev_num = num = value->enum_item->value;
191  num = htole64(num);
192  if (num == prev_num) {
193  /* values are equal, little-endian */
194  *dynamic = 0;
195  if (value_size_bits) {
196  *value_size_bits = fixed_size_bits;
197  }
198  return &value->enum_item->value;
199  } else {
200  /* values differ, big-endian */
201  buf = calloc(1, 4);
202  LY_CHECK_RET(!buf, NULL);
203 
204  *dynamic = 1;
205  if (value_size_bits) {
206  *value_size_bits = fixed_size_bits;
207  }
208  memcpy(buf, &num, 4);
209  return buf;
210  }
211  }
212 
213  /* use the cached canonical value */
214  if (dynamic) {
215  *dynamic = 0;
216  }
217  if (value_size_bits) {
218  *value_size_bits = strlen(value->_canonical) * 8;
219  }
220  return value->_canonical;
221 }
222 
231  {
232  .module = "",
233  .revision = NULL,
234  .name = LY_TYPE_ENUM_STR,
235 
236  .plugin.id = "ly2 enumeration",
237  .plugin.lyb_size = lyplg_type_lyb_size_enum,
238  .plugin.store = lyplg_type_store_enum,
239  .plugin.validate_value = NULL,
240  .plugin.validate_tree = NULL,
241  .plugin.compare = lyplg_type_compare_simple,
242  .plugin.sort = lyplg_type_sort_enum,
243  .plugin.print = lyplg_type_print_enum,
244  .plugin.duplicate = lyplg_type_dup_simple,
245  .plugin.free = lyplg_type_free_simple,
246  },
247  {0}
248 };
#define LYA_COUNT_T
Type (i.e. size) of the sized array&#39;s size counter.
Definition: ly_array.h:38
struct lysc_type * realtype
Definition: tree_data.h:615
Compiled YANG data node.
Definition: tree_schema.h:1430
#define LYA_FOR(ARRAY, INDEX)
Helper macro to go through sized-arrays with a numeric iterator.
Definition: ly_array.h:55
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
lyplg_lyb_size_type
Type of the LYB size of a value of a particular type.
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 dictionary
#define LYPLG_TYPE_STORE_DYNAMIC
struct lyplg_type_record plugins_enumeration[]
Plugin information for enumeration type implementation.
Definition: enumeration.c:230
YANG data representation.
Definition: tree_data.h:611
const char * _canonical
Definition: tree_data.h:612
Libyang full error structure.
Definition: log.h:301
Definition: log.h:293
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 sized array API.
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:263
const char * module
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: utils.h:93
struct lysc_type_bitenum_item * enums
Definition: tree_schema.h:1354
LY_DATA_TYPE basetype
Definition: tree_schema.h:1296
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.