2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
16 * Just make sure we include the prototype for strptime as well
17 * (needed for glibc 2.2) but make sure we do this only if not
26 #include <ftypes-int.h>
27 #include <epan/to_str.h>
30 #include "wsutil/strptime.h"
34 cmp_eq(const fvalue_t *a, const fvalue_t *b)
36 return ((a->value.time.secs) ==(b->value.time.secs))
37 &&((a->value.time.nsecs)==(b->value.time.nsecs));
40 cmp_ne(const fvalue_t *a, const fvalue_t *b)
42 return (a->value.time.secs !=b->value.time.secs)
43 ||(a->value.time.nsecs!=b->value.time.nsecs);
46 cmp_gt(const fvalue_t *a, const fvalue_t *b)
48 if (a->value.time.secs > b->value.time.secs) {
51 if (a->value.time.secs < b->value.time.secs) {
55 return a->value.time.nsecs > b->value.time.nsecs;
58 cmp_ge(const fvalue_t *a, const fvalue_t *b)
60 if (a->value.time.secs > b->value.time.secs) {
63 if (a->value.time.secs < b->value.time.secs) {
67 return a->value.time.nsecs >= b->value.time.nsecs;
70 cmp_lt(const fvalue_t *a, const fvalue_t *b)
72 if (a->value.time.secs < b->value.time.secs) {
75 if (a->value.time.secs > b->value.time.secs) {
79 return a->value.time.nsecs < b->value.time.nsecs;
82 cmp_le(const fvalue_t *a, const fvalue_t *b)
84 if (a->value.time.secs < b->value.time.secs) {
87 if (a->value.time.secs > b->value.time.secs) {
91 return a->value.time.nsecs <= b->value.time.nsecs;
96 * Get a nanoseconds value, starting at "p".
98 * Returns true on success, false on failure.
101 get_nsecs(const char *startp, int *nsecs)
111 * How many characters are in the string?
113 ndigits = (int)strlen(startp);
116 * If there are N characters in the string, the last of the
117 * characters would be the digit corresponding to 10^(9-N)
123 * Start at the last character, and work backwards.
125 p = startp + ndigits;
127 while (p != startp) {
130 if (!g_ascii_isdigit(*p)) {
132 * Not a digit - error.
139 * Non-zero digit corresponding to that number
140 * of (10^scale) units.
142 * If scale is less than zero, this digit corresponds
143 * to a value less than a nanosecond, so this number
148 for (i = 0; i < scale; i++)
159 relative_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
163 gboolean negative = FALSE;
173 * If it doesn't begin with ".", it should contain a seconds
176 if (*curptr != '.') {
178 * Get the seconds value.
180 fv->value.time.secs = strtoul(curptr, &endptr, 10);
181 if (endptr == curptr || (*endptr != '\0' && *endptr != '.'))
185 curptr++; /* skip the decimal point */
188 * No seconds value - it's 0.
190 fv->value.time.secs = 0;
191 curptr++; /* skip the decimal point */
195 * If there's more stuff left in the string, it should be the
198 if (*curptr != '\0') {
200 * Get the nanoseconds value.
202 if (!get_nsecs(curptr, &fv->value.time.nsecs))
206 * No nanoseconds value - it's 0.
208 fv->value.time.nsecs = 0;
212 fv->value.time.secs = -fv->value.time.secs;
213 fv->value.time.nsecs = -fv->value.time.nsecs;
219 *err_msg = g_strdup_printf("\"%s\" is not a valid time.", s);
225 absolute_val_from_string(fvalue_t *fv, const char *s, gchar **err_msg)
230 memset(&tm, 0, sizeof(tm));
231 curptr = strptime(s,"%b %d, %Y %H:%M:%S", &tm);
233 curptr = strptime(s,"%Y-%m-%dT%H:%M:%S", &tm);
235 curptr = strptime(s,"%Y-%m-%d %H:%M:%S", &tm);
237 curptr = strptime(s,"%Y-%m-%d %H:%M", &tm);
239 curptr = strptime(s,"%Y-%m-%d %H", &tm);
241 curptr = strptime(s,"%Y-%m-%d", &tm);
244 tm.tm_isdst = -1; /* let the computer figure out if it's DST */
245 fv->value.time.secs = mktime(&tm);
246 if (*curptr != '\0') {
248 * Something came after the seconds field; it must be
249 * a nanoseconds field.
252 goto fail; /* it's not */
253 curptr++; /* skip the "." */
254 if (!g_ascii_isdigit((unsigned char)*curptr))
255 goto fail; /* not a digit, so not valid */
256 if (!get_nsecs(curptr, &fv->value.time.nsecs))
260 * No nanoseconds value - it's 0.
262 fv->value.time.nsecs = 0;
265 if (fv->value.time.secs == -1) {
267 * XXX - should we supply an error message that mentions
268 * that the time specified might be syntactically valid
269 * but might not actually have occurred, e.g. a time in
270 * the non-existent time range after the clocks are
271 * set forward during daylight savings time (or possibly
272 * that it's in the time range after the clocks are set
273 * backward, so that there are two different times that
283 *err_msg = g_strdup_printf("\"%s\" is not a valid absolute time. Example: \"Nov 12, 1999 08:55:44.123\" or \"2011-07-04 12:34:56\"",
289 absolute_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
291 return absolute_val_from_string(fv, s, err_msg);
295 time_fvalue_new(fvalue_t *fv)
297 fv->value.time.secs = 0;
298 fv->value.time.nsecs = 0;
302 time_fvalue_set(fvalue_t *fv, const nstime_t *value)
304 fv->value.time = *value;
308 value_get(fvalue_t *fv)
310 return &(fv->value.time);
314 absolute_val_repr_len(fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
319 rep = abs_time_to_str(NULL, &fv->value.time, ABSOLUTE_TIME_LOCAL,
320 rtype == FTREPR_DISPLAY);
322 ret = (int)strlen(rep) + ((rtype == FTREPR_DFILTER) ? 2 : 0); /* 2 for opening and closing quotes */
324 wmem_free(NULL, rep);
330 absolute_val_to_repr(fvalue_t *fv, ftrepr_t rtype, int field_display _U_, char *buf, unsigned int size)
332 gchar *rep = abs_time_to_str(NULL, &fv->value.time, ABSOLUTE_TIME_LOCAL,
333 rtype == FTREPR_DISPLAY);
334 if (rtype == FTREPR_DFILTER) {
338 g_strlcpy(buf, rep, size);
340 if (rtype == FTREPR_DFILTER) {
345 wmem_free(NULL, rep);
349 relative_val_repr_len(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
354 rep = rel_time_to_secs_str(NULL, &fv->value.time);
355 ret = (int)strlen(rep);
356 wmem_free(NULL, rep);
362 relative_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf, unsigned int size)
365 rep = rel_time_to_secs_str(NULL, &fv->value.time);
366 g_strlcpy(buf, rep, size);
367 wmem_free(NULL, rep);
371 ftype_register_time(void)
374 static ftype_t abstime_type = {
375 FT_ABSOLUTE_TIME, /* ftype */
376 "FT_ABSOLUTE_TIME", /* name */
377 "Date and time", /* pretty_name */
379 time_fvalue_new, /* new_value */
380 NULL, /* free_value */
381 absolute_val_from_unparsed, /* val_from_unparsed */
382 absolute_val_from_string, /* val_from_string */
383 absolute_val_to_repr, /* val_to_string_repr */
384 absolute_val_repr_len, /* len_string_repr */
386 { .set_value_time = time_fvalue_set }, /* union set_value */
387 { .get_value_ptr = value_get }, /* union get_value */
395 NULL, /* cmp_bitwise_and */
396 NULL, /* cmp_contains */
397 NULL, /* cmp_matches */
402 static ftype_t reltime_type = {
403 FT_RELATIVE_TIME, /* ftype */
404 "FT_RELATIVE_TIME", /* name */
405 "Time offset", /* pretty_name */
407 time_fvalue_new, /* new_value */
408 NULL, /* free_value */
409 relative_val_from_unparsed, /* val_from_unparsed */
410 NULL, /* val_from_string */
411 relative_val_to_repr, /* val_to_string_repr */
412 relative_val_repr_len, /* len_string_repr */
414 { .set_value_time = time_fvalue_set }, /* union set_value */
415 { .get_value_ptr = value_get }, /* union get_value */
423 NULL, /* cmp_bitwise_and */
424 NULL, /* cmp_contains */
425 NULL, /* cmp_matches */
431 ftype_register(FT_ABSOLUTE_TIME, &abstime_type);
432 ftype_register(FT_RELATIVE_TIME, &reltime_type);
436 * Editor modelines - http://www.wireshark.org/tools/modelines.html
441 * indent-tabs-mode: t
444 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
445 * :indentSize=8:tabSize=8:noTabs=false: