libyang  2.1.148
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
bits.c
Go to the documentation of this file.
1 
15 #define _GNU_SOURCE /* strdup */
16 
17 #include "plugins_types.h"
18 
19 #include <ctype.h>
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 "common.h"
28 #include "compat.h"
29 #include "plugins_internal.h" /* LY_TYPE_*_STR */
30 
43 #define BITS_LAST_BIT_POSITION(type_bits) (type_bits->bits[LY_ARRAY_COUNT(type_bits->bits) - 1].position)
44 
48 #ifdef IS_BIG_ENDIAN
49 # define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + (size - 1) - idx)
50 #else
51 # define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + idx)
52 #endif
53 
54 LIBYANG_API_DEF size_t
56 {
57  size_t needed_bytes, size;
58 
59  LY_CHECK_ARG_RET(NULL, type, type->basetype == LY_TYPE_BITS, 0);
60 
61  /* minimum needed bytes to hold all the bit positions (which start at 0) */
62  needed_bytes = ((BITS_LAST_BIT_POSITION(type) + 1) / 8) + ((BITS_LAST_BIT_POSITION(type) + 1) % 8 ? 1 : 0);
63  LY_CHECK_ERR_RET(!needed_bytes, LOGINT(NULL), 0);
64 
65  if ((needed_bytes == 1) || (needed_bytes == 2)) {
66  /* uint8_t or uint16_t */
67  size = needed_bytes;
68  } else if (needed_bytes < 5) {
69  /* uint32_t */
70  size = 4;
71  } else if (needed_bytes < 9) {
72  /* uint64_t */
73  size = 8;
74  } else {
75  /* no basic type, do not round */
76  size = needed_bytes;
77  }
78 
79  return size;
80 }
81 
82 LIBYANG_API_DEF ly_bool
83 lyplg_type_bits_is_bit_set(const char *bitmap, size_t size, uint32_t bit_position)
84 {
85  char bitmask;
86 
87  /* find the byte with our bit */
88  (void)size;
89  bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
90  bit_position %= 8;
91 
92  /* generate bitmask */
93  bitmask = 1;
94  bitmask <<= bit_position;
95 
96  /* check if bit set */
97  if (*bitmap & bitmask) {
98  return 1;
99  }
100  return 0;
101 }
102 
110 static void
111 bits_bit_set(char *bitmap, size_t size, uint32_t bit_position)
112 {
113  char bitmask;
114 
115  /* find the byte with our bit */
116  (void)size;
117  bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
118  bit_position %= 8;
119 
120  /* generate bitmask */
121  bitmask = 1;
122  bitmask <<= bit_position;
123 
124  /* set the bit */
125  *bitmap |= bitmask;
126 }
127 
138 static LY_ERR
139 bits_str2bitmap(const char *value, size_t value_len, struct lysc_type_bits *type, char *bitmap, struct ly_err_item **err)
140 {
141  size_t idx_start, idx_end;
143  ly_bool found;
144 
145  idx_start = idx_end = 0;
146  while (idx_end < value_len) {
147  /* skip whitespaces */
148  while ((idx_end < value_len) && isspace(value[idx_end])) {
149  ++idx_end;
150  }
151  if (idx_end == value_len) {
152  break;
153  }
154 
155  /* parse bit name */
156  idx_start = idx_end;
157  while ((idx_end < value_len) && !isspace(value[idx_end])) {
158  ++idx_end;
159  }
160 
161  /* find the bit */
162  found = 0;
163  LY_ARRAY_FOR(type->bits, u) {
164  if (!ly_strncmp(type->bits[u].name, value + idx_start, idx_end - idx_start)) {
165  found = 1;
166  break;
167  }
168  }
169 
170  /* check if name exists */
171  if (!found) {
172  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid bit \"%.*s\".", (int)(idx_end - idx_start),
173  value + idx_start);
174  }
175 
176  /* check for duplication */
177  if (lyplg_type_bits_is_bit_set(bitmap, lyplg_type_bits_bitmap_size(type), type->bits[u].position)) {
178  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Duplicate bit \"%s\".", type->bits[u].name);
179  }
180 
181  /* set the bit */
182  bits_bit_set(bitmap, lyplg_type_bits_bitmap_size(type), type->bits[u].position);
183  }
184 
185  return LY_SUCCESS;
186 }
187 
195 static void
196 bits_add_item(uint32_t position, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items)
197 {
199 
200  /* find the bit item */
201  LY_ARRAY_FOR(type->bits, u) {
202  if (type->bits[u].position == position) {
203  break;
204  }
205  }
206 
207  /* add it at the end */
208  items[LY_ARRAY_COUNT(items)] = &type->bits[u];
209  LY_ARRAY_INCREMENT(items);
210 }
211 
219 static void
220 bits_bitmap2items(const char *bitmap, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items)
221 {
222  size_t i, bitmap_size = lyplg_type_bits_bitmap_size(type);
223  uint32_t bit_pos;
224  uint8_t bitmask;
225  const uint8_t *byte;
226 
227  bit_pos = 0;
228  for (i = 0; i < bitmap_size; ++i) {
229  /* check this byte (but not necessarily all bits in the last byte) */
230  byte = (uint8_t *)BITS_BITMAP_BYTE(bitmap, bitmap_size, i);
231  for (bitmask = 1; bitmask; bitmask <<= 1) {
232  if (*byte & bitmask) {
233  /* add this bit */
234  bits_add_item(bit_pos, type, items);
235  }
236 
237  if (bit_pos == BITS_LAST_BIT_POSITION(type)) {
238  /* we have checked the last valid bit */
239  break;
240  }
241 
242  ++bit_pos;
243  }
244  }
245 }
246 
254 static LY_ERR
255 bits_items2canon(struct lysc_type_bitenum_item **items, char **canonical)
256 {
257  char *ret;
258  size_t ret_len;
260 
261  *canonical = NULL;
262 
263  /* init value */
264  ret = strdup("");
265  LY_CHECK_RET(!ret, LY_EMEM);
266  ret_len = 0;
267 
268  LY_ARRAY_FOR(items, u) {
269  if (!ret_len) {
270  ret = ly_realloc(ret, strlen(items[u]->name) + 1);
271  LY_CHECK_RET(!ret, LY_EMEM);
272  strcpy(ret, items[u]->name);
273 
274  ret_len = strlen(ret);
275  } else {
276  ret = ly_realloc(ret, ret_len + 1 + strlen(items[u]->name) + 1);
277  LY_CHECK_RET(!ret, LY_EMEM);
278  sprintf(ret + ret_len, " %s", items[u]->name);
279 
280  ret_len += 1 + strlen(items[u]->name);
281  }
282  }
283 
284  *canonical = ret;
285  return LY_SUCCESS;
286 }
287 
288 LIBYANG_API_DEF LY_ERR
289 lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
290  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
291  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
292  struct ly_err_item **err)
293 {
294  LY_ERR ret = LY_SUCCESS;
295  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)type;
296  struct lyd_value_bits *val;
297 
298  /* init storage */
299  memset(storage, 0, sizeof *storage);
300  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
301  LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);
302  storage->realtype = type;
303 
304  if (format == LY_VALUE_LYB) {
305  /* validation */
306  if (value_len != lyplg_type_bits_bitmap_size(type_bits)) {
307  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB bits value size %zu (expected %zu).",
308  value_len, lyplg_type_bits_bitmap_size(type_bits));
309  goto cleanup;
310  }
311 
312  /* store value (bitmap) */
313  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
314  val->bitmap = (char *)value;
315  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
316  } else {
317  val->bitmap = malloc(value_len);
318  LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
319  memcpy(val->bitmap, value, value_len);
320  }
321 
322  /* allocate and fill the bit item array */
323  LY_ARRAY_CREATE_GOTO(ctx, val->items, LY_ARRAY_COUNT(type_bits->bits), ret, cleanup);
324  bits_bitmap2items(val->bitmap, type_bits, val->items);
325 
326  /* success */
327  goto cleanup;
328  }
329 
330  /* check hints */
331  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
332  LY_CHECK_GOTO(ret, cleanup);
333 
334  /* allocate the bitmap */
335  val->bitmap = malloc(lyplg_type_bits_bitmap_size(type_bits));
336  LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
337  memset(val->bitmap, 0, lyplg_type_bits_bitmap_size(type_bits));
338 
339  /* fill the bitmap */
340  ret = bits_str2bitmap(value, value_len, type_bits, val->bitmap, err);
341  LY_CHECK_GOTO(ret, cleanup);
342 
343  /* allocate and fill the bit item array */
344  LY_ARRAY_CREATE_GOTO(ctx, val->items, LY_ARRAY_COUNT(type_bits->bits), ret, cleanup);
345  bits_bitmap2items(val->bitmap, type_bits, val->items);
346 
347  if (format == LY_VALUE_CANON) {
348  /* store canonical value */
349  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
350  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
351  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
352  LY_CHECK_GOTO(ret, cleanup);
353  } else {
354  ret = lydict_insert(ctx, value_len ? value : "", value_len, &storage->_canonical);
355  LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
356  }
357  }
358 
359 cleanup:
360  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
361  free((void *)value);
362  }
363 
364  if (ret) {
365  lyplg_type_free_bits(ctx, storage);
366  }
367  return ret;
368 }
369 
370 LIBYANG_API_DEF LY_ERR
371 lyplg_type_compare_bits(const struct lyd_value *val1, const struct lyd_value *val2)
372 {
373  struct lyd_value_bits *v1, *v2;
374  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)val1->realtype;
375 
376  LYD_VALUE_GET(val1, v1);
377  LYD_VALUE_GET(val2, v2);
378 
379  if (memcmp(v1->bitmap, v2->bitmap, lyplg_type_bits_bitmap_size(type_bits))) {
380  return LY_ENOT;
381  }
382  return LY_SUCCESS;
383 }
384 
385 LIBYANG_API_DEF const void *
386 lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
387  void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
388 {
389  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)value->realtype;
390  struct lyd_value_bits *val;
391  char *ret;
392 
393  LYD_VALUE_GET(value, val);
394 
395  if (format == LY_VALUE_LYB) {
396  *dynamic = 0;
397  if (value_len) {
398  *value_len = lyplg_type_bits_bitmap_size(type_bits);
399  }
400  return val->bitmap;
401  }
402 
403  /* generate canonical value if not already */
404  if (!value->_canonical) {
405  /* get the canonical value */
406  if (bits_items2canon(val->items, &ret)) {
407  return NULL;
408  }
409 
410  /* store it */
411  if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
412  LOGMEM(ctx);
413  return NULL;
414  }
415  }
416 
417  /* use the cached canonical value */
418  if (dynamic) {
419  *dynamic = 0;
420  }
421  if (value_len) {
422  *value_len = strlen(value->_canonical);
423  }
424  return value->_canonical;
425 }
426 
427 LIBYANG_API_DEF LY_ERR
428 lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
429 {
430  LY_ERR ret;
431  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)original->realtype;
433  struct lyd_value_bits *orig_val, *dup_val;
434 
435  memset(dup, 0, sizeof *dup);
436 
437  /* optional canonical value */
438  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
439  LY_CHECK_GOTO(ret, error);
440 
441  /* allocate value */
442  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val);
443  LY_CHECK_ERR_GOTO(!dup_val, ret = LY_EMEM, error);
444 
445  LYD_VALUE_GET(original, orig_val);
446 
447  /* duplicate bitmap */
448  dup_val->bitmap = malloc(lyplg_type_bits_bitmap_size(type_bits));
449  LY_CHECK_ERR_GOTO(!dup_val->bitmap, ret = LY_EMEM, error);
450  memcpy(dup_val->bitmap, orig_val->bitmap, lyplg_type_bits_bitmap_size(type_bits));
451 
452  /* duplicate bit item pointers */
453  LY_ARRAY_CREATE_GOTO(ctx, dup_val->items, LY_ARRAY_COUNT(orig_val->items), ret, error);
454  LY_ARRAY_FOR(orig_val->items, u) {
455  LY_ARRAY_INCREMENT(dup_val->items);
456  dup_val->items[u] = orig_val->items[u];
457  }
458 
459  dup->realtype = original->realtype;
460  return LY_SUCCESS;
461 
462 error:
463  lyplg_type_free_bits(ctx, dup);
464  return ret;
465 }
466 
467 LIBYANG_API_DEF void
468 lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
469 {
470  struct lyd_value_bits *val;
471 
472  lydict_remove(ctx, value->_canonical);
473  value->_canonical = NULL;
474  LYD_VALUE_GET(value, val);
475  if (val) {
476  free(val->bitmap);
477  LY_ARRAY_FREE(val->items);
479  }
480 }
481 
489 const struct lyplg_type_record plugins_bits[] = {
490  {
491  .module = "",
492  .revision = NULL,
493  .name = LY_TYPE_BITS_STR,
494 
495  .plugin.id = "libyang 2 - bits, version 1",
496  .plugin.store = lyplg_type_store_bits,
497  .plugin.validate = NULL,
498  .plugin.compare = lyplg_type_compare_bits,
499  .plugin.sort = NULL,
500  .plugin.print = lyplg_type_print_bits,
501  .plugin.duplicate = lyplg_type_dup_bits,
502  .plugin.free = lyplg_type_free_bits,
503  .plugin.lyb_data_len = -1,
504  },
505  {0}
506 };
struct lysc_type * realtype
Definition: tree_data.h:564
Compiled YANG data node.
Definition: tree_schema.h:1414
struct lysc_type_bitenum_item * bits
Definition: tree_schema.h:1357
LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_format,...) _FORMAT_PRINTF(6
Create and fill error structure.
Definition: log.h:253
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:28
LIBYANG_API_DECL const void * lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len)
Implementation of the lyplg_type_print_clb for the built-in bits type.
#define LYPLG_TYPE_STORE_DYNAMIC
#define BITS_BITMAP_BYTE(bitmap, size, idx)
Get a specific byte in a bitmap.
Definition: bits.c:51
#define LOGMEM(CTX)
Definition: tree_edit.h:22
LIBYANG_API_DECL LY_ERR lyplg_type_compare_bits(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of the lyplg_type_compare_clb for the built-in bits type.
Definition: bits.c:371
#define LY_ARRAY_CREATE_GOTO(CTX, ARRAY, SIZE, RET, GOTO)
Allocate a (sized array) for the specified number of items. If the ARRAY already exists, it is resized (space for SIZE items is added).
Definition: tree_edit.h:186
LY_DATA_TYPE basetype
Definition: tree_schema.h:1355
struct lyplg_type_record plugins_bits[]
Plugin information for bits type implementation.
Definition: bits.c:489
The main libyang public header.
struct lysc_type_bitenum_item ** items
Definition: tree_data.h:635
#define BITS_LAST_BIT_POSITION(type_bits)
Get the position of the last bit.
Definition: bits.c:43
LIBYANG_API_DECL ly_bool lyplg_type_bits_is_bit_set(const char *bitmap, size_t size, uint32_t bit_position)
Check whether a particular bit of a bitmap is set.
Definition: bits.c:83
YANG data representation.
Definition: tree_data.h:560
const char * _canonical
Definition: tree_data.h:561
LIBYANG_API_DECL void lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
Implementation of the lyplg_type_free_clb for the built-in bits type.
Definition: bits.c:468
Libyang full error structure.
Definition: log.h:296
Definition: log.h:288
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:603
Definition: log.h:259
LIBYANG_API_DECL size_t lyplg_type_bits_bitmap_size(const struct lysc_type_bits *type)
Get the bitmap size of a bits value bitmap.
Definition: bits.c:55
#define LY_ARRAY_FREE(ARRAY)
Free the space allocated for the (sized array).
Definition: tree_edit.h:231
LIBYANG_API_DECL LY_ERR lydict_remove(const struct ly_ctx *ctx, const char *value)
Remove specified string from the dictionary. It decrement reference counter for the string and if it ...
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...
const char * name
LIBYANG_API_DECL 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&#39;s hints (if any) in the specified format.
const char * module
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
void * ly_realloc(void *ptr, size_t size)
Wrapper for realloc() call. The only difference is that if it fails to allocate the requested memory...
#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
Definition: log.h:265
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.
#define LYPLG_TYPE_VAL_INLINE_DESTROY(type_val)
Destroy a prepared value.
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:234
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
char * bitmap
Definition: tree_data.h:632
LY_DATA_TYPE basetype
Definition: tree_schema.h:1299
LIBYANG_API_DECL LY_ERR lyplg_type_store_bits(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 *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
Implementation of the lyplg_type_store_clb for the built-in bits type.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:251
#define LY_ARRAY_INCREMENT(ARRAY)
Increment the items counter in a (sized array).
Definition: tree_edit.h:197
LIBYANG_API_DECL LY_ERR lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
Implementation of the lyplg_type_dup_clb for the built-in bits type.
Definition: bits.c:428
Special lyd_value structure for built-in bits values.
Definition: tree_data.h:631
API for (user) types plugins.
libyang context handler.