libyang  4.0.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
decimal64.c
Go to the documentation of this file.
1 
16 #include "plugins_types.h"
17 
18 #include <stdint.h>
19 #include <stdlib.h>
20 
21 #include "libyang.h"
22 
23 /* additional internal headers for some useful simple macros */
24 #include "compat.h"
25 #include "ly_common.h"
26 #include "plugins_internal.h" /* LY_TYPE_*_STR */
27 
37 static LY_ERR lyplg_type_validate_value_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type,
38  struct lyd_value *storage, struct ly_err_item **err);
39 
48 static LY_ERR
49 decimal64_num2str(int64_t num, struct lysc_type_dec *type, char **str)
50 {
51  char *ret;
52 
53  /* allocate the value */
54  ret = calloc(1, LY_NUMBER_MAXLEN);
55  LY_CHECK_RET(!ret, LY_EMEM);
56 
57  if (num) {
58  int count = sprintf(ret, "%" PRId64 " ", num);
59 
60  if (((num > 0) && ((count - 1) <= type->fraction_digits)) || ((count - 2) <= type->fraction_digits)) {
61  /* we have 0. value, print the value with the leading zeros
62  * (one for 0. and also keep the correct with of num according
63  * to fraction-digits value)
64  * for (num < 0) - extra character for '-' sign */
65  count = sprintf(ret, "%0*" PRId64 " ", (num > 0) ? (type->fraction_digits + 1) : (type->fraction_digits + 2), num);
66  }
67  for (uint8_t i = type->fraction_digits, j = 1; i > 0; i--) {
68  if (j && (i > 1) && (ret[count - 2] == '0')) {
69  /* we have trailing zero to skip */
70  ret[count - 1] = '\0';
71  } else {
72  j = 0;
73  ret[count - 1] = ret[count - 2];
74  }
75  count--;
76  }
77  ret[count - 1] = '.';
78  } else {
79  /* zero */
80  sprintf(ret, "0.0");
81  }
82 
83  *str = ret;
84  return LY_SUCCESS;
85 }
86 
87 static void
88 lyplg_type_lyb_size_decimal64(const struct lysc_type *UNUSED(type), enum lyplg_lyb_size_type *size_type,
89  uint32_t *fixed_size_bits)
90 {
91  *size_type = LYPLG_LYB_SIZE_FIXED_BITS;
92  *fixed_size_bits = 64;
93 }
94 
95 static LY_ERR
96 lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint32_t value_size_bits,
97  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
98  const struct lysc_node *UNUSED(ctx_node), const struct lysc_ext_instance *UNUSED(top_ext),
99  struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
100 {
101  struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
102  LY_ERR ret = LY_SUCCESS;
103  uint32_t value_size;
104  int64_t num = 0;
105  char *canon;
106 
107  /* init storage */
108  memset(storage, 0, sizeof *storage);
109  storage->realtype = type;
110 
111  /* check value length */
112  ret = lyplg_type_check_value_size("decimal64", format, value_size_bits, LYPLG_LYB_SIZE_FIXED_BITS, 64, &value_size, err);
113  LY_CHECK_GOTO(ret, cleanup);
114 
115  if (format == LY_VALUE_LYB) {
116  /* we have the decimal64 number, in host byte order */
117  memcpy(&num, value, value_size);
118  num = le64toh(num);
119  } else {
120  /* check hints */
121  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
122  LY_CHECK_GOTO(ret, cleanup);
123 
124  /* parse decimal64 value */
125  ret = lyplg_type_parse_dec64(type_dec->fraction_digits, value, value_size, &num, err);
126  LY_CHECK_GOTO(ret, cleanup);
127  }
128 
129  /* store value */
130  storage->dec64 = num;
131 
132  /* we need canonical value for the range check */
133  if (format == LY_VALUE_CANON) {
134  /* store canonical value */
135  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
136  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
137  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
138  LY_CHECK_GOTO(ret, cleanup);
139  } else {
140  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
141  LY_CHECK_GOTO(ret, cleanup);
142  }
143  } else {
144  /* generate canonical value */
145  ret = decimal64_num2str(num, type_dec, &canon);
146  LY_CHECK_GOTO(ret, cleanup);
147 
148  /* store it */
149  ret = lydict_insert_zc(ctx, canon, (const char **)&storage->_canonical);
150  LY_CHECK_GOTO(ret, cleanup);
151  }
152 
153  if (!(options & LYPLG_TYPE_STORE_ONLY)) {
154  /* validate value */
155  ret = lyplg_type_validate_value_decimal64(ctx, type, storage, err);
156  LY_CHECK_GOTO(ret, cleanup);
157  }
158 
159 cleanup:
160  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
161  free((void *)value);
162  }
163 
164  if (ret) {
165  lyplg_type_free_simple(ctx, storage);
166  }
167  return ret;
168 }
169 
173 static LY_ERR
174 lyplg_type_validate_value_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type,
175  struct lyd_value *storage, struct ly_err_item **err)
176 {
177  LY_ERR ret;
178  struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
179  int64_t num;
180 
181  LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
182  *err = NULL;
183  num = storage->dec64;
184 
185  if (type_dec->range) {
186  /* check range of the number */
187  ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
188  strlen(storage->_canonical), err);
189  LY_CHECK_RET(ret);
190  }
191 
192  return LY_SUCCESS;
193 }
194 
195 static LY_ERR
196 lyplg_type_compare_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
197  const struct lyd_value *val2)
198 {
199  /* if type is the same, the fraction digits are, too */
200  if (val1->dec64 != val2->dec64) {
201  return LY_ENOT;
202  }
203  return LY_SUCCESS;
204 }
205 
206 static int
207 lyplg_type_sort_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
208 {
209  if (val1->dec64 > val2->dec64) {
210  return 1;
211  } else if (val1->dec64 < val2->dec64) {
212  return -1;
213  } else {
214  return 0;
215  }
216 }
217 
218 static const void *
219 lyplg_type_print_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
220  void *UNUSED(prefix_data), ly_bool *dynamic, uint32_t *value_size_bits)
221 {
222  int64_t num = 0;
223  void *buf;
224 
225  if (format == LY_VALUE_LYB) {
226  num = htole64(value->dec64);
227  if (num == value->dec64) {
228  /* values are equal, little-endian */
229  *dynamic = 0;
230  if (value_size_bits) {
231  *value_size_bits = sizeof value->dec64 * 8;
232  }
233  return &value->dec64;
234  } else {
235  /* values differ, big-endian */
236  buf = calloc(1, sizeof value->dec64);
237  LY_CHECK_RET(!buf, NULL);
238 
239  *dynamic = 1;
240  if (value_size_bits) {
241  *value_size_bits = sizeof value->dec64 * 8;
242  }
243  memcpy(buf, &num, sizeof value->dec64);
244  return buf;
245  }
246  }
247 
248  /* use the cached canonical value */
249  if (dynamic) {
250  *dynamic = 0;
251  }
252  if (value_size_bits) {
253  *value_size_bits = strlen(value->_canonical) * 8;
254  }
255  return value->_canonical;
256 }
257 
265 const struct lyplg_type_record plugins_decimal64[] = {
266  {
267  .module = "",
268  .revision = NULL,
269  .name = LY_TYPE_DEC64_STR,
270 
271  .plugin.id = "ly2 decimal64",
272  .plugin.lyb_size = lyplg_type_lyb_size_decimal64,
273  .plugin.store = lyplg_type_store_decimal64,
274  .plugin.validate_value = lyplg_type_validate_value_decimal64,
275  .plugin.validate_tree = NULL,
276  .plugin.compare = lyplg_type_compare_decimal64,
277  .plugin.sort = lyplg_type_sort_decimal64,
278  .plugin.print = lyplg_type_print_decimal64,
279  .plugin.duplicate = lyplg_type_dup_simple,
280  .plugin.free = lyplg_type_free_simple,
281  },
282  {0}
283 };
struct lysc_type * realtype
Definition: tree_data.h:567
Compiled YANG data node.
Definition: tree_schema.h:1434
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
LIBYANG_API_DECL LY_ERR lyplg_type_parse_dec64(uint8_t fraction_digits, const char *value, uint32_t value_len, int64_t *ret, struct ly_err_item **err)
Convert a string with a decimal64 value into libyang representation: ret = value * 10^fraction-digits...
struct lysc_range * range
Definition: tree_schema.h:1323
Definition: log.h:244
Definition: log.h:242
The main libyang public header.
uint8_t fraction_digits
Definition: tree_schema.h:1322
YANG data representation.
Definition: tree_data.h:563
const char * _canonical
Definition: tree_data.h:564
Libyang full error structure.
Definition: log.h:285
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 * module
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
LY_DATA_TYPE basetype
Definition: tree_schema.h:1300
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.
LIBYANG_API_DECL LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval, uint32_t strval_len, struct ly_err_item **err)
Data type validator for a range/length-restricted values.
#define LYPLG_TYPE_STORE_ONLY