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