libyang  2.2.8
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 
15 #include "plugins_types.h"
16 
17 #include <stdint.h>
18 #include <stdlib.h>
19 
20 #include "libyang.h"
21 
22 /* additional internal headers for some useful simple macros */
23 #include "compat.h"
24 #include "ly_common.h"
25 #include "plugins_internal.h" /* LY_TYPE_*_STR */
26 
36 static LY_ERR lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);
37 
46 static LY_ERR
47 decimal64_num2str(int64_t num, struct lysc_type_dec *type, char **str)
48 {
49  char *ret;
50 
51  /* allocate the value */
52  ret = calloc(1, LY_NUMBER_MAXLEN);
53  LY_CHECK_RET(!ret, LY_EMEM);
54 
55  if (num) {
56  int count = sprintf(ret, "%" PRId64 " ", num);
57 
58  if (((num > 0) && ((count - 1) <= type->fraction_digits)) || ((count - 2) <= type->fraction_digits)) {
59  /* we have 0. value, print the value with the leading zeros
60  * (one for 0. and also keep the correct with of num according
61  * to fraction-digits value)
62  * for (num < 0) - extra character for '-' sign */
63  count = sprintf(ret, "%0*" PRId64 " ", (num > 0) ? (type->fraction_digits + 1) : (type->fraction_digits + 2), num);
64  }
65  for (uint8_t i = type->fraction_digits, j = 1; i > 0; i--) {
66  if (j && (i > 1) && (ret[count - 2] == '0')) {
67  /* we have trailing zero to skip */
68  ret[count - 1] = '\0';
69  } else {
70  j = 0;
71  ret[count - 1] = ret[count - 2];
72  }
73  count--;
74  }
75  ret[count - 1] = '.';
76  } else {
77  /* zero */
78  sprintf(ret, "0.0");
79  }
80 
81  *str = ret;
82  return LY_SUCCESS;
83 }
84 
85 LIBYANG_API_DEF LY_ERR
86 lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
87  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
88  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
89  struct ly_err_item **err)
90 {
91  struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
92  LY_ERR ret = LY_SUCCESS;
93  int64_t num;
94  char *canon;
95 
96  /* init storage */
97  memset(storage, 0, sizeof *storage);
98  storage->realtype = type;
99 
100  if (format == LY_VALUE_LYB) {
101  /* validation */
102  if (value_len != 8) {
103  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB decimal64 value size %zu (expected 8).",
104  value_len);
105  goto cleanup;
106  }
107 
108  /* we have the decimal64 number, in host byte order */
109  memcpy(&num, value, value_len);
110  num = le64toh(num);
111  } else {
112  /* check hints */
113  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
114  LY_CHECK_GOTO(ret, cleanup);
115 
116  /* parse decimal64 value */
117  ret = lyplg_type_parse_dec64(type_dec->fraction_digits, value, value_len, &num, err);
118  LY_CHECK_GOTO(ret, cleanup);
119  }
120 
121  /* store value */
122  storage->dec64 = num;
123 
124  /* we need canonical value for the range check */
125  if (format == LY_VALUE_CANON) {
126  /* store canonical value */
127  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
128  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
129  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
130  LY_CHECK_GOTO(ret, cleanup);
131  } else {
132  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
133  LY_CHECK_GOTO(ret, cleanup);
134  }
135  } else {
136  /* generate canonical value */
137  ret = decimal64_num2str(num, type_dec, &canon);
138  LY_CHECK_GOTO(ret, cleanup);
139 
140  /* store it */
141  ret = lydict_insert_zc(ctx, canon, (const char **)&storage->_canonical);
142  LY_CHECK_GOTO(ret, cleanup);
143  }
144 
145  if (!(options & LYPLG_TYPE_STORE_ONLY)) {
146  /* validate value */
147  ret = lyplg_type_validate_decimal64(ctx, type, NULL, NULL, storage, err);
148  LY_CHECK_GOTO(ret, cleanup);
149  }
150 
151 cleanup:
152  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
153  free((void *)value);
154  }
155 
156  if (ret) {
157  lyplg_type_free_simple(ctx, storage);
158  }
159  return ret;
160 }
161 
165 static LY_ERR
166 lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
167  const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
168 {
169  LY_ERR ret;
170  struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
171  int64_t num;
172 
173  LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
174  *err = NULL;
175  num = storage->dec64;
176 
177  if (type_dec->range) {
178  /* check range of the number */
179  ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
180  strlen(storage->_canonical), err);
181  LY_CHECK_RET(ret);
182  }
183 
184  return LY_SUCCESS;
185 }
186 
187 LIBYANG_API_DEF LY_ERR
188 lyplg_type_compare_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
189  const struct lyd_value *val2)
190 {
191  /* if type is the same, the fraction digits are, too */
192  if (val1->dec64 != val2->dec64) {
193  return LY_ENOT;
194  }
195  return LY_SUCCESS;
196 }
197 
198 LIBYANG_API_DEF int
199 lyplg_type_sort_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
200 {
201  if (val1->dec64 > val2->dec64) {
202  return 1;
203  } else if (val1->dec64 < val2->dec64) {
204  return -1;
205  } else {
206  return 0;
207  }
208 }
209 
210 LIBYANG_API_DEF const void *
211 lyplg_type_print_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
212  void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
213 {
214  int64_t num = 0;
215  void *buf;
216 
217  if (format == LY_VALUE_LYB) {
218  num = htole64(value->dec64);
219  if (num == value->dec64) {
220  /* values are equal, little-endian */
221  *dynamic = 0;
222  if (value_len) {
223  *value_len = sizeof value->dec64;
224  }
225  return &value->dec64;
226  } else {
227  /* values differ, big-endian */
228  buf = calloc(1, sizeof value->dec64);
229  LY_CHECK_RET(!buf, NULL);
230 
231  *dynamic = 1;
232  if (value_len) {
233  *value_len = sizeof value->dec64;
234  }
235  memcpy(buf, &num, sizeof value->dec64);
236  return buf;
237  }
238  }
239 
240  /* use the cached canonical value */
241  if (dynamic) {
242  *dynamic = 0;
243  }
244  if (value_len) {
245  *value_len = strlen(value->_canonical);
246  }
247  return value->_canonical;
248 }
249 
257 const struct lyplg_type_record plugins_decimal64[] = {
258  {
259  .module = "",
260  .revision = NULL,
261  .name = LY_TYPE_DEC64_STR,
262 
263  .plugin.id = "libyang 2 - decimal64, version 1",
264  .plugin.store = lyplg_type_store_decimal64,
265  .plugin.validate = lyplg_type_validate_decimal64,
266  .plugin.compare = lyplg_type_compare_decimal64,
267  .plugin.sort = lyplg_type_sort_decimal64,
268  .plugin.print = lyplg_type_print_decimal64,
269  .plugin.duplicate = lyplg_type_dup_simple,
270  .plugin.free = lyplg_type_free_simple,
271  .plugin.lyb_data_len = 8,
272  },
273  {0}
274 };
struct lysc_type * realtype
Definition: tree_data.h:575
Compiled YANG data node.
Definition: tree_schema.h:1439
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
Definition: log.h:244
Generic structure for a data node.
Definition: tree_data.h:799
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:28
Definition: log.h:242
#define LYPLG_TYPE_STORE_DYNAMIC
struct lysc_range * range
Definition: tree_schema.h:1328
LIBYANG_API_DECL LY_ERR lyplg_type_compare_decimal64(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in decimal64 type.
The main libyang public header.
uint8_t fraction_digits
Definition: tree_schema.h:1327
YANG data representation.
Definition: tree_data.h:571
const char * _canonical
Definition: tree_data.h:572
Libyang full error structure.
Definition: log.h:285
LIBYANG_API_DECL LY_ERR lyplg_type_store_decimal64(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 lyplg_type_store_clb for the built-in decimal64 type.
Definition: log.h:277
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 lyplg_type_parse_dec64(uint8_t fraction_digits, const char *value, size_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...
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...
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
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
LIBYANG_API_DECL const void * lyplg_type_print_decimal64(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 lyplg_type_print_clb for the built-in decimal64 type.
LY_DATA_TYPE basetype
Definition: tree_schema.h:1305
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_DEF int lyplg_type_sort_decimal64(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_sort_clb for the built-in decimal64 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.
API for (user) types plugins.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:240
libyang context handler.
#define LYPLG_TYPE_STORE_ONLY
Definition: log.h:254
LIBYANG_API_DECL LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval, size_t strval_len, struct ly_err_item **err)
Data type validator for a range/length-restricted values.