libyang  2.0.164
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 "common.h"
24 #include "compat.h"
25 #include "plugins_internal.h" /* LY_TYPE_*_STR */
26 
44 static LY_ERR
45 decimal64_num2str(int64_t num, struct lysc_type_dec *type, char **str)
46 {
47  char *ret;
48 
49  /* allocate the value */
50  ret = calloc(1, LY_NUMBER_MAXLEN);
51  LY_CHECK_RET(!ret, LY_EMEM);
52 
53  if (num) {
54  int count = sprintf(ret, "%" PRId64 " ", num);
55  if (((num > 0) && ((count - 1) <= type->fraction_digits)) || ((count - 2) <= type->fraction_digits)) {
56  /* we have 0. value, print the value with the leading zeros
57  * (one for 0. and also keep the correct with of num according
58  * to fraction-digits value)
59  * for (num < 0) - extra character for '-' sign */
60  count = sprintf(ret, "%0*" PRId64 " ", (num > 0) ? (type->fraction_digits + 1) : (type->fraction_digits + 2), num);
61  }
62  for (uint8_t i = type->fraction_digits, j = 1; i > 0; i--) {
63  if (j && (i > 1) && (ret[count - 2] == '0')) {
64  /* we have trailing zero to skip */
65  ret[count - 1] = '\0';
66  } else {
67  j = 0;
68  ret[count - 1] = ret[count - 2];
69  }
70  count--;
71  }
72  ret[count - 1] = '.';
73  } else {
74  /* zero */
75  sprintf(ret, "0.0");
76  }
77 
78  *str = ret;
79  return LY_SUCCESS;
80 }
81 
82 LIBYANG_API_DEF LY_ERR
83 lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
84  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
85  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
86  struct ly_err_item **err)
87 {
88  struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
89  LY_ERR ret = LY_SUCCESS;
90  int64_t num;
91  char *canon;
92 
93  /* init storage */
94  memset(storage, 0, sizeof *storage);
95  storage->realtype = type;
96 
97  if (format == LY_VALUE_LYB) {
98  /* validation */
99  if (value_len != 8) {
100  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB decimal64 value size %zu (expected 8).",
101  value_len);
102  goto cleanup;
103  }
104 
105  /* we have the decimal64 number, in host byte order */
106  memcpy(&num, value, value_len);
107  num = le64toh(num);
108  } else {
109  /* check hints */
110  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
111  LY_CHECK_GOTO(ret, cleanup);
112 
113  /* parse decimal64 value */
114  ret = lyplg_type_parse_dec64(type_dec->fraction_digits, value, value_len, &num, err);
115  LY_CHECK_GOTO(ret, cleanup);
116  }
117 
118  /* store value */
119  storage->dec64 = num;
120 
121  /* we need canonical value for the range check */
122  if (format == LY_VALUE_CANON) {
123  /* store canonical value */
124  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
125  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
126  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
127  LY_CHECK_GOTO(ret, cleanup);
128  } else {
129  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
130  LY_CHECK_GOTO(ret, cleanup);
131  }
132  } else {
133  /* generate canonical value */
134  ret = decimal64_num2str(num, type_dec, &canon);
135  LY_CHECK_GOTO(ret, cleanup);
136 
137  /* store it */
138  ret = lydict_insert_zc(ctx, canon, (const char **)&storage->_canonical);
139  LY_CHECK_GOTO(ret, cleanup);
140  }
141 
142  if (type_dec->range) {
143  /* check range of the number */
144  ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
145  strlen(storage->_canonical), err);
146  LY_CHECK_GOTO(ret, cleanup);
147  }
148 
149 cleanup:
150  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
151  free((void *)value);
152  }
153 
154  if (ret) {
155  lyplg_type_free_simple(ctx, storage);
156  }
157  return ret;
158 }
159 
160 LIBYANG_API_DEF LY_ERR
161 lyplg_type_compare_decimal64(const struct lyd_value *val1, const struct lyd_value *val2)
162 {
163  if (val1->realtype != val2->realtype) {
164  return LY_ENOT;
165  }
166 
167  /* if type is the same, the fraction digits are, too */
168  if (val1->dec64 != val2->dec64) {
169  return LY_ENOT;
170  }
171  return LY_SUCCESS;
172 }
173 
174 LIBYANG_API_DEF const void *
175 lyplg_type_print_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
176  void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
177 {
178  int64_t num = 0;
179  void *buf;
180 
181  if (format == LY_VALUE_LYB) {
182  num = htole64(value->dec64);
183  if (num == value->dec64) {
184  /* values are equal, little-endian */
185  *dynamic = 0;
186  if (value_len) {
187  *value_len = sizeof value->dec64;
188  }
189  return &value->dec64;
190  } else {
191  /* values differ, big-endian */
192  buf = calloc(1, sizeof value->dec64);
193  LY_CHECK_RET(!buf, NULL);
194 
195  *dynamic = 1;
196  if (value_len) {
197  *value_len = sizeof value->dec64;
198  }
199  memcpy(buf, &num, sizeof value->dec64);
200  return buf;
201  }
202  }
203 
204  /* use the cached canonical value */
205  if (dynamic) {
206  *dynamic = 0;
207  }
208  if (value_len) {
209  *value_len = strlen(value->_canonical);
210  }
211  return value->_canonical;
212 }
213 
222  {
223  .module = "",
224  .revision = NULL,
225  .name = LY_TYPE_DEC64_STR,
226 
227  .plugin.id = "libyang 2 - decimal64, version 1",
228  .plugin.store = lyplg_type_store_decimal64,
229  .plugin.validate = NULL,
230  .plugin.compare = lyplg_type_compare_decimal64,
231  .plugin.sort = NULL,
232  .plugin.print = lyplg_type_print_decimal64,
233  .plugin.duplicate = lyplg_type_dup_simple,
234  .plugin.free = lyplg_type_free_simple,
235  .plugin.lyb_data_len = 8,
236  },
237  {0}
238 };
struct lysc_type * realtype
Definition: tree_data.h:552
Compiled YANG data node.
Definition: tree_schema.h:1666
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:249
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:27
#define LYPLG_TYPE_STORE_DYNAMIC
struct lysc_range * range
Definition: tree_schema.h:1571
The main libyang public header.
uint8_t fraction_digits
Definition: tree_schema.h:1570
YANG data representation.
Definition: tree_data.h:548
const char * _canonical
Definition: tree_data.h:549
Libyang full error structure.
Definition: log.h:292
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:284
Definition: log.h:255
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 lyplg_type_compare_decimal64(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in decimal64 type.
Definition: decimal64.c:161
Definition: log.h:261
struct lyplg_type_record plugins_decimal64[]
Plugin information for decimal64 type implementation.
Definition: decimal64.c:221
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:235
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:1552
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.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:247
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.
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, size_t strval_len, struct ly_err_item **err)
Data type validator for a range/length-restricted values.