libyang  6.3.1
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
date.c
Go to the documentation of this file.
1 
15 #define _GNU_SOURCE /* strdup */
16 #define _XOPEN_SOURCE /* strptime */
17 
18 #include "plugins_types.h"
19 
20 #include <assert.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 
28 #include "compat.h"
29 #include "dict.h"
30 #include "ly_common.h"
31 #include "plugins_internal.h"
32 
43 static void lyplg_type_free_date(const struct ly_ctx *ctx, struct lyd_value *value);
44 
45 static void
46 lyplg_type_lyb_size_date_nz(const struct lysc_type *UNUSED(type), enum lyplg_lyb_size_type *size_type,
47  uint64_t *fixed_size_bits)
48 {
49  *size_type = LYPLG_LYB_SIZE_FIXED_BITS;
50  *fixed_size_bits = 64;
51 }
52 
56 static LY_ERR
57 lyplg_type_store_date(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
58  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
59  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
60  struct ly_err_item **err)
61 {
62  LY_ERR ret = LY_SUCCESS;
63  struct lyd_value_date *val = NULL;
64  struct lyd_value_date_nz *val_nz = NULL;
65  struct tm tm = {0};
66  char *ptr;
67  uint32_t value_size;
68  char *str = NULL;
69 
70  /* init storage */
71  memset(storage, 0, sizeof *storage);
72  if (!strcmp(type->name, "date")) {
73  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
74  } else {
75  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val_nz);
76  }
77  LY_CHECK_ERR_GOTO(!val && !val_nz, ret = LY_EMEM, cleanup);
78  storage->realtype = type;
79 
80  if (format == LY_VALUE_LYB) {
81  /* validation */
82  if (val) {
83  if ((value_size_bits != 64) && (value_size_bits != 65)) {
84  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB %s value size %" PRIu64
85  " b (expected 64 or 65 b).", type->name, value_size_bits);
86  goto cleanup;
87  }
88  } else {
89  if (value_size_bits != 64) {
90  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB %s value size %" PRIu64
91  " b (expected 64 b).", type->name, value_size_bits);
92  goto cleanup;
93  }
94  }
95  value_size = LYPLG_BITS2BYTES(value_size_bits);
96 
97  /* store timestamp */
98  if (val) {
99  memcpy(&val->time, value, sizeof val->time);
100  } else {
101  memcpy(&val_nz->time, value, sizeof val_nz->time);
102  }
103 
104  /* store unknown timezone */
105  if (val && (value_size > 8)) {
106  val->unknown_tz = *(((uint8_t *)value) + 8) ? 1 : 0;
107  }
108 
109  /* success */
110  goto cleanup;
111  }
112 
113  /* get value byte length */
114  if (val) {
115  ret = lyplg_type_check_value_size(type->name, format, value_size_bits, LYPLG_LYB_SIZE_VARIABLE_BITS, 0,
116  &value_size, err);
117  } else {
118  ret = lyplg_type_check_value_size(type->name, format, value_size_bits, LYPLG_LYB_SIZE_FIXED_BITS, 64,
119  &value_size, err);
120  }
121  LY_CHECK_GOTO(ret, cleanup);
122 
123  /* check hints */
124  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
125  LY_CHECK_GOTO(ret, cleanup);
126 
127  if (!(options & LYPLG_TYPE_STORE_ONLY)) {
128  /* validate value */
129  ret = lyplg_type_validate_patterns(ctx, ((struct lysc_type_str *)type)->patterns, value, value_size, err);
130  LY_CHECK_RET(ret);
131  }
132 
133  if (val) {
134  /* create date-and-time value */
135  if (asprintf(&str, "%.*sT00:00:00%.*s", 10, (char *)value, (int)(value_size - 10), (char *)value + 10) == -1) {
136  ret = LY_EMEM;
137  goto cleanup;
138  }
139 
140  /* convert to UNIX time */
141  ret = ly_time_str2time(str, &val->time, NULL);
142  if (ret) {
143  ret = ly_err_new(err, ret, 0, NULL, NULL, "%s", ly_last_logmsg());
144  goto cleanup;
145  }
146  } else {
147  /* fill tm */
148  ptr = strptime(value, "%Y-%m-%d", &tm);
149  if (!ptr || ((uint32_t)(ptr - (char *)value) != value_size)) {
150  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Failed to parse %s value \"%.*s\".", type->name,
151  (int)value_size, (char *)value);
152  goto cleanup;
153  }
154 
155  /* convert to UNIX time */
156  val_nz->time = timegm(&tm);
157  }
158 
159  if (val && (((char *)value)[value_size - 1] == 'Z')) {
160  /* unknown timezone */
161  val->unknown_tz = 1;
162  }
163 
164  if (format == LY_VALUE_CANON) {
165  /* store canonical value */
166  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
167  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
168  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
169  LY_CHECK_GOTO(ret, cleanup);
170  } else {
171  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
172  LY_CHECK_GOTO(ret, cleanup);
173  }
174  }
175 
176 cleanup:
177  free(str);
178  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
179  free((void *)value);
180  }
181 
182  if (ret) {
183  lyplg_type_free_date(ctx, storage);
184  }
185  return ret;
186 }
187 
191 static LY_ERR
192 lyplg_type_compare_date(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
193  const struct lyd_value *val2)
194 {
195  struct lyd_value_date *v1, *v2;
196  struct lyd_value_date_nz *vn1, *vn2;
197 
198  if (!strcmp(val1->realtype->name, "date")) {
199  LYD_VALUE_GET(val1, v1);
200  LYD_VALUE_GET(val2, v2);
201 
202  /* compare timestamp and unknown tz */
203  if ((v1->time != v2->time) || (v1->unknown_tz != v2->unknown_tz)) {
204  return LY_ENOT;
205  }
206  } else {
207  LYD_VALUE_GET(val1, vn1);
208  LYD_VALUE_GET(val2, vn2);
209 
210  /* compare timestamp */
211  if (vn1->time != vn2->time) {
212  return LY_ENOT;
213  }
214  }
215 
216  return LY_SUCCESS;
217 }
218 
222 static int
223 lyplg_type_sort_date(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
224 {
225  struct lyd_value_date *v1, *v2;
227 
228  if (!strcmp(val1->realtype->name, "date")) {
229  LYD_VALUE_GET(val1, v1);
230  LYD_VALUE_GET(val2, v2);
231 
232  /* compare timestamps */
233  return difftime(v1->time, v2->time);
234  } else {
235  LYD_VALUE_GET(val1, vn1);
236  LYD_VALUE_GET(val2, vn2);
237 
238  /* compare timestamps */
239  return difftime(vn1->time, vn2->time);
240  }
241 }
242 
246 static const void *
247 lyplg_type_print_date(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
248  void *UNUSED(prefix_data), ly_bool *dynamic, uint64_t *value_size_bits)
249 {
250  struct lyd_value_date *val = NULL;
251  struct lyd_value_date_nz *val_nz = NULL;
252  struct tm tm;
253  char *ret;
254 
255  if (!strcmp(value->realtype->name, "date")) {
256  LYD_VALUE_GET(value, val);
257  } else {
258  LYD_VALUE_GET(value, val_nz);
259  }
260 
261  if (format == LY_VALUE_LYB) {
262  if (val && val->unknown_tz) {
263  ret = malloc(8 + 1);
264  LY_CHECK_ERR_RET(!ret, LOGMEM(ctx), NULL);
265 
266  *dynamic = 1;
267  if (value_size_bits) {
268  *value_size_bits = 64 + 8;
269  }
270  memcpy(ret, &val->time, sizeof val->time);
271  memcpy(ret + 8, &val->unknown_tz, sizeof val->unknown_tz);
272  } else {
273  *dynamic = 0;
274  if (value_size_bits) {
275  *value_size_bits = 64;
276  }
277  ret = val ? (char *)&val->time : (char *)&val_nz->time;
278  }
279  return ret;
280  }
281 
282  /* generate canonical value if not already */
283  if (!value->_canonical) {
284  if (val_nz || (val && val->unknown_tz)) {
285  /* ly_time_time2str but always using GMT */
286  if (!gmtime_r(val_nz ? &val_nz->time : &val->time, &tm)) {
287  return NULL;
288  }
289 
290  if (asprintf(&ret, "%04d-%02d-%02d%s", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, val ? "Z" : "") == -1) {
291  return NULL;
292  }
293  } else {
294  if (ly_time_time2str(val->time, NULL, &ret)) {
295  return NULL;
296  }
297 
298  /* truncate the time segment */
299  assert(ret[10] == 'T');
300  memmove(ret + 10, ret + 19, strlen(ret + 19) + 1);
301  }
302 
303  /* store it */
304  if (lydict_insert(ctx, ret, 0, (const char **)&value->_canonical)) {
305  free(ret);
306  LOGMEM(ctx);
307  return NULL;
308  }
309  free(ret);
310  }
311 
312  /* use the cached canonical value */
313  if (dynamic) {
314  *dynamic = 0;
315  }
316  if (value_size_bits) {
317  *value_size_bits = strlen(value->_canonical) * 8;
318  }
319  return value->_canonical;
320 }
321 
325 static LY_ERR
326 lyplg_type_dup_date(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
327 {
328  LY_ERR ret;
329  struct lyd_value_date *orig_val, *dup_val;
330  struct lyd_value_date *orig_val_nz, *dup_val_nz;
331 
332  memset(dup, 0, sizeof *dup);
333 
334  /* optional canonical value */
335  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
336  LY_CHECK_GOTO(ret, error);
337 
338  /* allocate value */
339  if (!strcmp(original->realtype->name, "date")) {
340  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val);
341  LY_CHECK_ERR_GOTO(!dup_val, ret = LY_EMEM, error);
342 
343  LYD_VALUE_GET(original, orig_val);
344 
345  /* copy timestamp and unknown tz */
346  dup_val->time = orig_val->time;
347  dup_val->unknown_tz = orig_val->unknown_tz;
348  } else {
349  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val_nz);
350  LY_CHECK_ERR_GOTO(!dup_val_nz, ret = LY_EMEM, error);
351 
352  LYD_VALUE_GET(original, orig_val_nz);
353 
354  /* copy timestamp */
355  dup_val_nz->time = orig_val_nz->time;
356  }
357 
358  dup->realtype = original->realtype;
359  return LY_SUCCESS;
360 
361 error:
362  lyplg_type_free_date(ctx, dup);
363  return ret;
364 }
365 
369 static void
370 lyplg_type_free_date(const struct ly_ctx *ctx, struct lyd_value *value)
371 {
372  struct lyd_value_date *val, *val_nz;
373 
374  lydict_remove(ctx, value->_canonical);
375  value->_canonical = NULL;
376 
377  if (!strcmp(value->realtype->name, "date")) {
378  LYD_VALUE_GET(value, val);
379  if (val) {
381  }
382  } else {
383  LYD_VALUE_GET(value, val_nz);
384  if (val_nz) {
386  }
387  }
388 }
389 
397 const struct lyplg_type_record plugins_date[] = {
398  {
399  .module = "ietf-yang-types",
400  .revision = NULL,
401  .name = "date",
402 
403  .plugin.id = "ly2 date",
404  .plugin.lyb_size = lyplg_type_lyb_size_variable_bytes,
405  .plugin.store = lyplg_type_store_date,
406  .plugin.validate_value = lyplg_type_validate_value_string,
407  .plugin.validate_tree = NULL,
408  .plugin.compare = lyplg_type_compare_date,
409  .plugin.sort = lyplg_type_sort_date,
410  .plugin.print = lyplg_type_print_date,
411  .plugin.duplicate = lyplg_type_dup_date,
412  .plugin.free = lyplg_type_free_date,
413  },
414  {
415  .module = "ietf-yang-types",
416  .revision = NULL,
417  .name = "date-no-zone",
418 
419  .plugin.id = "ly2 date",
420  .plugin.lyb_size = lyplg_type_lyb_size_date_nz,
421  .plugin.store = lyplg_type_store_date,
422  .plugin.validate_value = lyplg_type_validate_value_string,
423  .plugin.validate_tree = NULL,
424  .plugin.compare = lyplg_type_compare_date,
425  .plugin.sort = lyplg_type_sort_date,
426  .plugin.print = lyplg_type_print_date,
427  .plugin.duplicate = lyplg_type_dup_date,
428  .plugin.free = lyplg_type_free_date,
429  },
430  {0}
431 };
return difftime(vn1->time, vn2->time)
Special lyd_value structure for ietf-yang-types date-no-zone values.
Definition: tree_data.h:764
struct lysc_type * realtype
Definition: tree_data.h:615
Compiled YANG data node.
Definition: tree_schema.h:1430
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
LIBYANG_API_DECL LY_ERR ly_time_time2str(time_t time, const char *fractions_s, char **str)
Convert UNIX timestamp and fractions of a second into canonical date-and-time string value...
lyplg_lyb_size_type
Type of the LYB size of a value of a particular type.
Special lyd_value structure for ietf-yang-types date values.
Definition: tree_data.h:756
LIBYANG_API_DECL void lyplg_type_lyb_size_variable_bytes(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint64_t *fixed_size_bits)
Implementation of lyplg_type_lyb_size_clb for a type with variable length rounded to bytes...
struct lyplg_type_record plugins_date[]
Plugin information for date and date-no-zone type implementation.
Definition: date.c:397
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:255
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:29
LIBYANG_API_DECL LY_ERR lyplg_type_check_value_size(const char *type_name, LY_VALUE_FORMAT format, uint64_t value_size_bits, enum lyplg_lyb_size_type lyb_size_type, uint64_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.
libyang dictionary
Definition: log.h:269
#define LYPLG_TYPE_STORE_DYNAMIC
LIBYANG_API_DECL LY_ERR lyplg_type_validate_patterns(const struct ly_ctx *ctx, struct lysc_pattern **patterns, const char *str, uint32_t str_len, struct ly_err_item **err)
Data type validator for pattern-restricted string values.
ly_bool unknown_tz
Definition: tree_data.h:758
LIBYANG_API_DECL LY_ERR ly_time_str2time(const char *value, time_t *time, char **fractions_s)
Convert date-and-time from string to UNIX timestamp and fractions of a second.
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
Definition: log.h:257
YANG data representation.
Definition: tree_data.h:611
const char * _canonical
Definition: tree_data.h:612
Libyang full error structure.
Definition: log.h:301
Definition: log.h:293
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:654
LIBYANG_API_DECL LY_ERR lyplg_type_validate_value_string(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *storage, struct ly_err_item **err)
Implementation of lyplg_type_validate_value_clb for the string type.
Definition: string.c:116
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 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...
struct lyd_value_date_nz * vn2
Definition: date.c:226
const char * name
Definition: tree_schema.h:1293
Definition: log.h:263
const char * module
struct lyd_value_date_nz * vn1
Definition: date.c:226
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: utils.h:93
LIBYANG_API_DECL const char * ly_last_logmsg(void)
Get the last (thread-specific) full logged error message.
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
LY_DATA_TYPE basetype
Definition: tree_schema.h:1296
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.
#define LYPLG_TYPE_STORE_ONLY
assert(!value->_canonical)