libyang  6.4.13
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
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 
230 const struct lyplg_type_record plugins_enumeration[] = {
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 };
libyang dictionary
const struct lyplg_type_record plugins_enumeration[]
Plugin information for enumeration type implementation.
Definition: enumeration.c:230
#define LYA_FOR(ARRAY, INDEX)
Helper macro to go through sized-arrays with a numeric iterator.
Definition: ly_array.h:55
#define LYA_COUNT_T
Type (i.e. size) of the sized array's size counter.
Definition: ly_array.h:38
libyang context handler.
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...
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,...
LY_ERR
libyang's error codes returned by the libyang functions.
Definition: log.h:252
@ LYVE_DATA
Definition: log.h:290
@ LY_EVALID
Definition: log.h:260
@ LY_SUCCESS
Definition: log.h:253
Libyang full error structure.
Definition: log.h:298
const char * module
lyplg_lyb_size_type
Type of the LYB size of a value of a particular 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's hints (if any) in the specified format.
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...
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 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 an error structure.
@ LYPLG_LYB_SIZE_FIXED_BITS
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_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.
#define LYPLG_TYPE_STORE_DYNAMIC
LY_DATA_TYPE basetype
Definition: tree_schema.h:1278
struct lysc_type_bitenum_item * enums
Definition: tree_schema.h:1336
Compiled YANG data node.
Definition: tree_schema.h:1412
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:29
libyang sized array API.
API for (user) types plugins.
const struct lysc_type * realtype
Definition: tree_data.h:614
const char * _canonical
Definition: tree_data.h:611
YANG data representation.
Definition: tree_data.h:610
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: utils.h:93
@ LY_VALUE_LYB
Definition: utils.h:100