libyang  3.1.0
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 "compat.h"
28 #include "ly_common.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 ly_ctx *UNUSED(ctx), 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 int
386 lyplg_type_sort_bits(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
387 {
388  struct lyd_value_binary *v1, *v2;
389  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)val1->realtype;
390  int cmp;
391 
392  LYD_VALUE_GET(val1, v1);
393  LYD_VALUE_GET(val2, v2);
394 
395  cmp = memcmp(v1->data, v2->data, lyplg_type_bits_bitmap_size(type_bits));
396 
397  return cmp;
398 }
399 
400 LIBYANG_API_DEF const void *
401 lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
402  void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
403 {
404  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)value->realtype;
405  struct lyd_value_bits *val;
406  char *ret;
407 
408  LYD_VALUE_GET(value, val);
409 
410  if (format == LY_VALUE_LYB) {
411  *dynamic = 0;
412  if (value_len) {
413  *value_len = lyplg_type_bits_bitmap_size(type_bits);
414  }
415  return val->bitmap;
416  }
417 
418  /* generate canonical value if not already */
419  if (!value->_canonical) {
420  /* get the canonical value */
421  if (bits_items2canon(val->items, &ret)) {
422  return NULL;
423  }
424 
425  /* store it */
426  if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
427  LOGMEM(ctx);
428  return NULL;
429  }
430  }
431 
432  /* use the cached canonical value */
433  if (dynamic) {
434  *dynamic = 0;
435  }
436  if (value_len) {
437  *value_len = strlen(value->_canonical);
438  }
439  return value->_canonical;
440 }
441 
442 LIBYANG_API_DEF LY_ERR
443 lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
444 {
445  LY_ERR ret;
446  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)original->realtype;
448  struct lyd_value_bits *orig_val, *dup_val;
449 
450  memset(dup, 0, sizeof *dup);
451 
452  /* optional canonical value */
453  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
454  LY_CHECK_GOTO(ret, error);
455 
456  /* allocate value */
457  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val);
458  LY_CHECK_ERR_GOTO(!dup_val, ret = LY_EMEM, error);
459 
460  LYD_VALUE_GET(original, orig_val);
461 
462  /* duplicate bitmap */
463  dup_val->bitmap = malloc(lyplg_type_bits_bitmap_size(type_bits));
464  LY_CHECK_ERR_GOTO(!dup_val->bitmap, ret = LY_EMEM, error);
465  memcpy(dup_val->bitmap, orig_val->bitmap, lyplg_type_bits_bitmap_size(type_bits));
466 
467  /* duplicate bit item pointers */
468  LY_ARRAY_CREATE_GOTO(ctx, dup_val->items, LY_ARRAY_COUNT(orig_val->items), ret, error);
469  LY_ARRAY_FOR(orig_val->items, u) {
470  LY_ARRAY_INCREMENT(dup_val->items);
471  dup_val->items[u] = orig_val->items[u];
472  }
473 
474  dup->realtype = original->realtype;
475  return LY_SUCCESS;
476 
477 error:
478  lyplg_type_free_bits(ctx, dup);
479  return ret;
480 }
481 
482 LIBYANG_API_DEF void
483 lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
484 {
485  struct lyd_value_bits *val;
486 
487  lydict_remove(ctx, value->_canonical);
488  value->_canonical = NULL;
489  LYD_VALUE_GET(value, val);
490  if (val) {
491  free(val->bitmap);
492  LY_ARRAY_FREE(val->items);
494  }
495 }
496 
504 const struct lyplg_type_record plugins_bits[] = {
505  {
506  .module = "",
507  .revision = NULL,
508  .name = LY_TYPE_BITS_STR,
509 
510  .plugin.id = "libyang 2 - bits, version 1",
511  .plugin.store = lyplg_type_store_bits,
512  .plugin.validate = NULL,
513  .plugin.compare = lyplg_type_compare_bits,
514  .plugin.sort = lyplg_type_sort_bits,
515  .plugin.print = lyplg_type_print_bits,
516  .plugin.duplicate = lyplg_type_dup_bits,
517  .plugin.free = lyplg_type_free_bits,
518  .plugin.lyb_data_len = -1,
519  },
520  {0}
521 };
struct lysc_type * realtype
Definition: tree_data.h:575
LIBYANG_API_DEF int lyplg_type_sort_bits(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of the lyplg_type_sort_clb for the built-in bits type.
Compiled YANG data node.
Definition: tree_schema.h:1439
struct lysc_type_bitenum_item * bits
Definition: tree_schema.h:1373
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:28
Definition: log.h:242
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
#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:1370
struct lyplg_type_record plugins_bits[]
Plugin information for bits type implementation.
Definition: bits.c:504
int cmp
Definition: binary.c:382
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
The main libyang public header.
struct lysc_type_bitenum_item ** items
Definition: tree_data.h:646
#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:571
const char * _canonical
Definition: tree_data.h:572
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:483
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:614
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 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.
struct lysc_type_bits * type_bits
Definition: bits.c:374
const char * module
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
LIBYANG_API_DECL LY_ERR lyplg_type_compare_bits(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of the lyplg_type_compare_clb for the built-in bits type.
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
Definition: log.h:248
#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:643
LY_DATA_TYPE basetype
Definition: tree_schema.h:1305
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.
#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:443
Special lyd_value structure for built-in bits values.
Definition: tree_data.h:642
API for (user) types plugins.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:240
libyang context handler.
Special lyd_value structure for built-in binary values.
Definition: tree_data.h:653
Definition: log.h:254