libyang  4.0.3
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 
16 #define _GNU_SOURCE /* strdup */
17 
18 #include "plugins_types.h"
19 
20 #include <ctype.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "libyang.h"
26 
27 /* additional internal headers for some useful simple macros */
28 #include "compat.h"
29 #include "ly_common.h"
30 #include "plugins_internal.h" /* LY_TYPE_*_STR */
31 
41 static void lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value);
42 
46 #define BITS_LAST_BIT_POSITION(type_bits) ((type_bits)->bits[LY_ARRAY_COUNT((type_bits)->bits) - 1].position)
47 
51 #ifdef IS_BIG_ENDIAN
52 # define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + (size - 1) - idx)
53 #else
54 # define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + idx)
55 #endif
56 
57 LIBYANG_API_DEF ly_bool
58 lyplg_type_bits_is_bit_set(const char *bitmap, uint32_t size_bits, uint32_t bit_position)
59 {
60  char bitmask;
61  uint32_t size;
62 
63  /* get size in bytes */
64  size = size_bits / 8 + (size_bits % 8) ? 1 : 0;
65 
66  /* find the byte with our bit */
67  (void)size;
68  bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
69  bit_position %= 8;
70 
71  /* generate bitmask */
72  bitmask = 1;
73  bitmask <<= bit_position;
74 
75  /* check if bit set */
76  if (*bitmap & bitmask) {
77  return 1;
78  }
79  return 0;
80 }
81 
89 static void
90 bits_bit_set(char *bitmap, uint32_t size_bits, uint32_t bit_position)
91 {
92  char bitmask;
93  uint32_t size;
94 
95  /* get size in bytes */
96  size = size_bits / 8 + (size_bits % 8) ? 1 : 0;
97 
98  /* find the byte with our bit */
99  (void)size;
100  bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
101  bit_position %= 8;
102 
103  /* generate bitmask */
104  bitmask = 1;
105  bitmask <<= bit_position;
106 
107  /* set the bit */
108  *bitmap |= bitmask;
109 }
110 
111 static void
112 lyplg_type_lyb_size_bits(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint32_t *fixed_size_bits)
113 {
114  const struct lysc_type_bits *type_bits = (struct lysc_type_bits *)type;
115 
116  /* position of the last bit, positions start at 0, add 1 */
117  *size_type = LYPLG_LYB_SIZE_FIXED_BITS;
118  *fixed_size_bits = BITS_LAST_BIT_POSITION(type_bits) + 1;
119 }
120 
131 static LY_ERR
132 bits_str2bitmap(const char *value, uint32_t value_len, struct lysc_type_bits *type, char *bitmap, struct ly_err_item **err)
133 {
134  uint32_t idx_start, idx_end;
136  ly_bool found;
137 
138  idx_start = idx_end = 0;
139  while (idx_end < value_len) {
140  /* skip whitespaces */
141  while ((idx_end < value_len) && isspace(value[idx_end])) {
142  ++idx_end;
143  }
144  if (idx_end == value_len) {
145  break;
146  }
147 
148  /* parse bit name */
149  idx_start = idx_end;
150  while ((idx_end < value_len) && !isspace(value[idx_end])) {
151  ++idx_end;
152  }
153 
154  /* find the bit */
155  found = 0;
156  LY_ARRAY_FOR(type->bits, u) {
157  if (!ly_strncmp(type->bits[u].name, value + idx_start, idx_end - idx_start)) {
158  found = 1;
159  break;
160  }
161  }
162 
163  /* check if name exists */
164  if (!found) {
165  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid bit \"%.*s\".", (int)(idx_end - idx_start),
166  value + idx_start);
167  }
168 
169  /* check for duplication */
170  if (lyplg_type_bits_is_bit_set(bitmap, BITS_LAST_BIT_POSITION(type) + 1, type->bits[u].position)) {
171  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Duplicate bit \"%s\".", type->bits[u].name);
172  }
173 
174  /* set the bit */
175  bits_bit_set(bitmap, BITS_LAST_BIT_POSITION(type) + 1, type->bits[u].position);
176  }
177 
178  return LY_SUCCESS;
179 }
180 
188 static void
189 bits_add_item(uint32_t position, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items)
190 {
192 
193  /* find the bit item */
194  LY_ARRAY_FOR(type->bits, u) {
195  if (type->bits[u].position == position) {
196  break;
197  }
198  }
199 
200  /* add it at the end */
201  items[LY_ARRAY_COUNT(items)] = &type->bits[u];
202  LY_ARRAY_INCREMENT(items);
203 }
204 
212 static void
213 bits_bitmap2items(const char *bitmap, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items)
214 {
215  uint32_t bit_pos, i, bitmap_size;
216  uint8_t bitmask;
217  const uint8_t *byte;
218 
219  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION(type) + 1);
220 
221  bit_pos = 0;
222  for (i = 0; i < bitmap_size; ++i) {
223  /* check this byte (but not necessarily all bits in the last byte) */
224  byte = (uint8_t *)BITS_BITMAP_BYTE(bitmap, bitmap_size, i);
225  for (bitmask = 1; bitmask; bitmask <<= 1) {
226  if (*byte & bitmask) {
227  /* add this bit */
228  bits_add_item(bit_pos, type, items);
229  }
230 
231  if (bit_pos == BITS_LAST_BIT_POSITION(type)) {
232  /* we have checked the last valid bit */
233  break;
234  }
235 
236  ++bit_pos;
237  }
238  }
239 }
240 
248 static LY_ERR
249 bits_items2canon(struct lysc_type_bitenum_item **items, char **canonical)
250 {
251  char *ret;
252  uint32_t ret_len;
254 
255  *canonical = NULL;
256 
257  /* init value */
258  ret = strdup("");
259  LY_CHECK_RET(!ret, LY_EMEM);
260  ret_len = 0;
261 
262  LY_ARRAY_FOR(items, u) {
263  if (!ret_len) {
264  ret = ly_realloc(ret, strlen(items[u]->name) + 1);
265  LY_CHECK_RET(!ret, LY_EMEM);
266  strcpy(ret, items[u]->name);
267 
268  ret_len = strlen(ret);
269  } else {
270  ret = ly_realloc(ret, ret_len + 1 + strlen(items[u]->name) + 1);
271  LY_CHECK_RET(!ret, LY_EMEM);
272  sprintf(ret + ret_len, " %s", items[u]->name);
273 
274  ret_len += 1 + strlen(items[u]->name);
275  }
276  }
277 
278  *canonical = ret;
279  return LY_SUCCESS;
280 }
281 
282 static LY_ERR
283 lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint32_t value_size_bits,
284  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
285  const struct lysc_node *UNUSED(ctx_node), const struct lysc_ext_instance *UNUSED(top_ext),
286  struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
287 {
288  LY_ERR ret = LY_SUCCESS;
289  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)type;
290  struct lyd_value_bits *val;
291  uint32_t value_size;
292 
293  /* init storage */
294  memset(storage, 0, sizeof *storage);
295  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
296  LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);
297  storage->realtype = type;
298 
299  /* check value length */
300  ret = lyplg_type_check_value_size("bits", format, value_size_bits, LYPLG_LYB_SIZE_FIXED_BITS,
301  BITS_LAST_BIT_POSITION(type_bits) + 1, &value_size, err);
302  LY_CHECK_GOTO(ret, cleanup);
303 
304  if (format == LY_VALUE_LYB) {
305  /* store value (bitmap) */
306  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
307  val->bitmap = (char *)value;
308  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
309  } else {
310  val->bitmap = malloc(value_size);
311  LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
312  memcpy(val->bitmap, value, value_size);
313  }
314 
315  /* allocate and fill the bit item array */
316  LY_ARRAY_CREATE_GOTO(ctx, val->items, LY_ARRAY_COUNT(type_bits->bits), ret, cleanup);
317  bits_bitmap2items(val->bitmap, type_bits, val->items);
318 
319  /* success */
320  goto cleanup;
321  }
322 
323  /* check hints */
324  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
325  LY_CHECK_GOTO(ret, cleanup);
326 
327  /* allocate the bitmap */
328  val->bitmap = calloc(1, LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION(type_bits) + 1));
329  LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
330 
331  /* fill the bitmap */
332  ret = bits_str2bitmap(value, value_size, type_bits, val->bitmap, err);
333  LY_CHECK_GOTO(ret, cleanup);
334 
335  /* allocate and fill the bit item array */
336  LY_ARRAY_CREATE_GOTO(ctx, val->items, LY_ARRAY_COUNT(type_bits->bits), ret, cleanup);
337  bits_bitmap2items(val->bitmap, type_bits, val->items);
338 
339  if (format == LY_VALUE_CANON) {
340  /* store canonical value */
341  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
342  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
343  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
344  LY_CHECK_GOTO(ret, cleanup);
345  } else {
346  ret = lydict_insert(ctx, value_size ? value : "", value_size, &storage->_canonical);
347  LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
348  }
349  }
350 
351 cleanup:
352  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
353  free((void *)value);
354  }
355 
356  if (ret) {
357  lyplg_type_free_bits(ctx, storage);
358  }
359  return ret;
360 }
361 
362 static LY_ERR
363 lyplg_type_compare_bits(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
364 {
365  struct lyd_value_bits *v1, *v2;
366  uint32_t bitmap_size;
367 
368  LYD_VALUE_GET(val1, v1);
369  LYD_VALUE_GET(val2, v2);
370 
371  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION((struct lysc_type_bits *)val1->realtype) + 1);
372 
373  if (memcmp(v1->bitmap, v2->bitmap, bitmap_size)) {
374  return LY_ENOT;
375  }
376  return LY_SUCCESS;
377 }
378 
379 static int
380 lyplg_type_sort_bits(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
381 {
382  struct lyd_value_binary *v1, *v2;
383  uint32_t bitmap_size;
384 
385  LYD_VALUE_GET(val1, v1);
386  LYD_VALUE_GET(val2, v2);
387 
388  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION((struct lysc_type_bits *)val1->realtype) + 1);
389 
390  return memcmp(v1->data, v2->data, bitmap_size);
391 }
392 
393 static const void *
394 lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
395  void *UNUSED(prefix_data), ly_bool *dynamic, uint32_t *value_len_bits)
396 {
397  struct lyd_value_bits *val;
398  char *ret;
399 
400  LYD_VALUE_GET(value, val);
401 
402  if (format == LY_VALUE_LYB) {
403  *dynamic = 0;
404  if (value_len_bits) {
405  *value_len_bits = BITS_LAST_BIT_POSITION((struct lysc_type_bits *)value->realtype) + 1;
406  }
407  return val->bitmap;
408  }
409 
410  /* generate canonical value if not already */
411  if (!value->_canonical) {
412  /* get the canonical value */
413  if (bits_items2canon(val->items, &ret)) {
414  return NULL;
415  }
416 
417  /* store it */
418  if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
419  LOGMEM(ctx);
420  return NULL;
421  }
422  }
423 
424  /* use the cached canonical value */
425  if (dynamic) {
426  *dynamic = 0;
427  }
428  if (value_len_bits) {
429  *value_len_bits = strlen(value->_canonical) * 8;
430  }
431  return value->_canonical;
432 }
433 
434 static LY_ERR
435 lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
436 {
437  LY_ERR ret;
439  struct lyd_value_bits *orig_val, *dup_val;
440  uint32_t bitmap_size;
441 
442  memset(dup, 0, sizeof *dup);
443 
444  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION((struct lysc_type_bits *)original->realtype) + 1);
445 
446  /* optional canonical value */
447  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
448  LY_CHECK_GOTO(ret, error);
449 
450  /* allocate value */
451  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val);
452  LY_CHECK_ERR_GOTO(!dup_val, ret = LY_EMEM, error);
453 
454  LYD_VALUE_GET(original, orig_val);
455 
456  /* duplicate bitmap */
457  dup_val->bitmap = malloc(bitmap_size);
458  LY_CHECK_ERR_GOTO(!dup_val->bitmap, ret = LY_EMEM, error);
459  memcpy(dup_val->bitmap, orig_val->bitmap, bitmap_size);
460 
461  /* duplicate bit item pointers */
462  LY_ARRAY_CREATE_GOTO(ctx, dup_val->items, LY_ARRAY_COUNT(orig_val->items), ret, error);
463  LY_ARRAY_FOR(orig_val->items, u) {
464  LY_ARRAY_INCREMENT(dup_val->items);
465  dup_val->items[u] = orig_val->items[u];
466  }
467 
468  dup->realtype = original->realtype;
469  return LY_SUCCESS;
470 
471 error:
472  lyplg_type_free_bits(ctx, dup);
473  return ret;
474 }
475 
476 static void
477 lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
478 {
479  struct lyd_value_bits *val;
480 
481  lydict_remove(ctx, value->_canonical);
482  value->_canonical = NULL;
483  LYD_VALUE_GET(value, val);
484  if (val) {
485  free(val->bitmap);
486  LY_ARRAY_FREE(val->items);
488  }
489 }
490 
498 const struct lyplg_type_record plugins_bits[] = {
499  {
500  .module = "",
501  .revision = NULL,
502  .name = LY_TYPE_BITS_STR,
503 
504  .plugin.id = "ly2 bits",
505  .plugin.lyb_size = lyplg_type_lyb_size_bits,
506  .plugin.store = lyplg_type_store_bits,
507  .plugin.validate_value = NULL,
508  .plugin.validate_tree = NULL,
509  .plugin.compare = lyplg_type_compare_bits,
510  .plugin.sort = lyplg_type_sort_bits,
511  .plugin.print = lyplg_type_print_bits,
512  .plugin.duplicate = lyplg_type_dup_bits,
513  .plugin.free = lyplg_type_free_bits,
514  },
515  {0}
516 };
struct lysc_type * realtype
Definition: tree_data.h:567
LIBYANG_API_DECL ly_bool lyplg_type_bits_is_bit_set(const char *bitmap, uint32_t size_bits, uint32_t bit_position)
Check whether a particular bit of a bitmap is set.
Definition: bits.c:58
Compiled YANG data node.
Definition: tree_schema.h:1434
struct lysc_type_bitenum_item * bits
Definition: tree_schema.h:1368
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
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
Definition: log.h:254
#define LYPLG_TYPE_STORE_DYNAMIC
#define BITS_BITMAP_BYTE(bitmap, size, idx)
Get a specific byte in a bitmap.
Definition: bits.c:54
#define LOGMEM(CTX)
Definition: tree_edit.h:22
#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
struct lyplg_type_record plugins_bits[]
Plugin information for bits type implementation.
Definition: bits.c:498
const char * name
Definition: tree_schema.h:1362
uint32_t bitmap_size
Definition: bits.c:366
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
Definition: log.h:242
The main libyang public header.
struct lysc_type_bitenum_item ** items
Definition: tree_data.h:639
#define BITS_LAST_BIT_POSITION(type_bits)
Get the position of the last bit.
Definition: bits.c:46
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
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:606
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.
#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...
Definition: log.h:248
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
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.
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:636
LY_DATA_TYPE basetype
Definition: tree_schema.h:1300
return memcmp(v1->data, v2->data, bitmap_size)
#define LY_ARRAY_INCREMENT(ARRAY)
Increment the items counter in a (sized array).
Definition: tree_edit.h:197
Special lyd_value structure for built-in bits values.
Definition: tree_data.h:635
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.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
Special lyd_value structure for built-in binary values.
Definition: tree_data.h:646