Build with NetBSD's strptime()

Replace our strptime code, which is from gnulib,
with the simpler and better NetBSD implementation.

This changes the ws_strptime() stub to unconditionally use
the internal implementation. Previously it would use the
system implementation of available. This is still possible
but is opt-in, i.e., code should add the necessary #ifdefs
and assume responsability for handling non-portable formats
or providing limited functionality on some platforms.

Text import allows the user to specify the strptime()
format freely, so in that case it makes sense to use the
system's implementation, and pass the responsability
for understanding the implementation and the supported
specifiers to the user.

Only fall back to our implementation if the system libc
lacks a strptime().
This commit is contained in:
João Valverde 2023-09-02 22:57:53 +01:00
parent 718d852ed0
commit fe802272a2
14 changed files with 175 additions and 1138 deletions

View File

@ -86,6 +86,7 @@ check_symbol_exists("timespec_get" "time.h" HAVE_TIMESPEC_GET)
if(NOT MSVC)
check_symbol_exists("localtime_r" "time.h" HAVE_LOCALTIME_R)
check_symbol_exists("tzset" "time.h" HAVE_TZSET)
check_symbol_exists("tzname" "time.h" HAVE_TZNAME)
endif()
check_function_exists("getifaddrs" HAVE_GETIFADDRS)
check_function_exists("issetugid" HAVE_ISSETUGID)
@ -114,9 +115,7 @@ check_struct_has_member("struct stat" st_blksize sys/stat.h HAVE_STRUC
check_struct_has_member("struct stat" st_birthtime sys/stat.h HAVE_STRUCT_STAT_ST_BIRTHTIME)
check_struct_has_member("struct stat" __st_birthtime sys/stat.h HAVE_STRUCT_STAT___ST_BIRTHTIME)
check_struct_has_member("struct tm" tm_zone time.h HAVE_STRUCT_TM_TM_ZONE)
#Symbols but NOT enums or types
check_symbol_exists(tzname "time.h" HAVE_TZNAME)
check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_STRUCT_TM_TM_GMTOFF)
# Types
include(CheckTypeSize)

View File

@ -307,6 +307,9 @@
/* Define to 1 if you have the <sys/wait.h> header file. */
#cmakedefine HAVE_SYS_WAIT_H 1
/* Define if tm_gmtoff field exists in struct tm */
#cmakedefine HAVE_STRUCT_TM_TM_GMTOFF 1
/* Define if tm_zone field exists in struct tm */
#cmakedefine HAVE_STRUCT_TM_TM_ZONE 1

View File

@ -15,6 +15,7 @@
#include <epan/to_str.h>
#include <wsutil/time_util.h>
#include <wsutil/ws_strptime.h>
#include <wsutil/safe-math.h>

View File

@ -12,7 +12,7 @@
#include "config.h"
#define WS_LOG_DOMAIN "ciscodump"
#include <extcap/extcap-base.h>
#include <wsutil/interface.h>
#include <wsutil/strtoi.h>
@ -28,6 +28,7 @@
#include <fcntl.h>
#include <wsutil/time_util.h>
#include <wsutil/ws_strptime.h>
#include <cli_main.h>

View File

@ -21,3 +21,5 @@ Insecure.Com LLC ("The Nmap Project") has granted the Wireshark Foundation permi
We use the overflow-safe math functions from the [portable snippets](https://github.com/nemequ/portable-snippets) repository.
We use the [Lrexlib](https://github.com/rrthomas/lrexlib) Lua library, specifically the PCRE2 flavour, to provide a regular expression API for Lua.
The code for our `strptime()` implementation is from [NetBSD](https://www.netbsd.org/).

View File

@ -74,6 +74,7 @@
* not supported and no automatic format detection is attempted.
*/
#define _GNU_SOURCE /* For strptime() */
#include "config.h"
#include "text_import.h"
@ -98,6 +99,7 @@
#include <wsutil/nstime.h>
#include <wsutil/time_util.h>
#include <wsutil/ws_strptime.h>
#include <wsutil/version_info.h>
#include <wsutil/cpu_info.h>
@ -352,6 +354,16 @@ static hdr_export_pdu_t HDR_EXPORT_PDU = {0, 0};
#define EXPORT_PDU_END_OF_OPTIONS_SIZE 4
static char *
text_import_strptime(const char *buf, const char *format, struct tm *restrict tm)
{
#ifdef HAVE_STRPTIME
return strptime(buf, format, tm);
#else
return ws_strptime(buf, format, tm);
#endif
}
/*----------------------------------------------------------------------
* Parse a single hex number
* Will abort the program if it can't parse the number
@ -1079,7 +1091,7 @@ _parse_time(const guchar* start_field, const guchar* end_field, const gchar* _fo
*subsecs_fmt = 0;
}
cursor = ws_strptime(cursor, format, &timecode);
cursor = text_import_strptime(cursor, format, &timecode);
if (cursor == NULL) {
return FALSE;
@ -1096,7 +1108,7 @@ _parse_time(const guchar* start_field, const guchar* end_field, const gchar* _fo
subseclen = (int) (p - cursor);
cursor = p;
cursor = ws_strptime(cursor, subsecs_fmt + 2, &timecode);
cursor = text_import_strptime(cursor, subsecs_fmt + 2, &timecode);
if (cursor == NULL) {
return FALSE;
}

View File

@ -83,9 +83,6 @@ indent_size = 2
indent_style = tab
indent_size = tab
[strptime.[ch]]
indent_size = 2
[tempfile.[ch]]
indent_size = 2
@ -114,5 +111,9 @@ indent_size = tab
[ws_mempbrk_sse42.[ch]]
indent_size = 2
[ws_strptime.[ch]]
indent_style = tab
indent_size = tab
[wsgetopt.[ch]]
indent_size = 2

View File

@ -140,6 +140,7 @@ set(WSUTIL_PUBLIC_HEADERS
ws_pipe.h
ws_roundup.h
ws_return.h
ws_strptime.h
wsgcrypt.h
wsjson.h
wslog.h
@ -200,6 +201,7 @@ set(WSUTIL_COMMON_FILES
ws_getopt.c
ws_mempbrk.c
ws_pipe.c
ws_strptime.c
wsgcrypt.c
wsjson.c
wslog.c
@ -304,10 +306,6 @@ if(HAVE_SSE4_2)
list(APPEND WSUTIL_FILES ws_mempbrk_sse42.c)
endif()
if(NOT HAVE_STRPTIME)
list(APPEND WSUTIL_FILES strptime.c)
endif()
if(APPLE)
#
# We assume that APPLE means macOS so that we have the macOS

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
/** @file
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __STRPTIME_H__
#define __STRPTIME_H__
#include <ws_symbol_export.h>
#include <time.h>
/*
* Version of "strptime()", for the benefit of OSes that don't have it.
*/
WS_DLL_LOCAL
char *strptime_gnulib(const char *s, const char *format, struct tm *tm);
#endif

View File

@ -7,7 +7,6 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#define _GNU_SOURCE /* For strptime(). */
#include "config.h"
#define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL
#include "time_util.h"
@ -21,10 +20,6 @@
#include <windows.h>
#endif
#ifndef HAVE_STRPTIME
#include "strptime.h"
#endif
/* Test if the given year is a leap year */
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
@ -240,16 +235,6 @@ ws_clock_get_realtime(struct timespec *ts)
#endif
}
char *ws_strptime(const char *restrict s, const char *restrict format,
struct tm *restrict tm)
{
#ifdef HAVE_STRPTIME
return strptime(s, format, tm);
#else
return strptime_gnulib(s, format, tm);
#endif
}
struct tm *
ws_localtime_r(const time_t *timep, struct tm *result)
{

View File

@ -65,12 +65,6 @@ guint64 create_timestamp(void);
WS_DLL_PUBLIC
struct timespec *ws_clock_get_realtime(struct timespec *ts);
/*
* Portability wrapper around strptime().
*/
WS_DLL_PUBLIC
char *ws_strptime(const char *s, const char *format, struct tm *tm);
WS_DLL_PUBLIC
struct tm *ws_localtime_r(const time_t *timep, struct tm *result);

View File

@ -1,5 +1,3 @@
/* $NetBSD: strptime.c,v 1.63 2020/09/21 15:31:54 ginsbach Exp $ */
/*-
* Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
@ -28,34 +26,96 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "ws_strptime.h"
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: strptime.c,v 1.63 2020/09/21 15:31:54 ginsbach Exp $");
#include <wsutil/time_util.h>
#ifdef _WIN32
#define tzset _tzset
#define tzname _tzname
#define timezone _timezone
#define daylight _daylight
#endif
#include "namespace.h"
#include <sys/localedef.h>
#include <sys/types.h>
#include <ctype.h>
#include <locale.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include "private.h"
#include "setlocale_local.h"
#ifdef __weak_alias
__weak_alias(strptime,_strptime)
__weak_alias(strptime_l, _strptime_l)
#ifdef HAVE_STRUCT_TM_TM_ZONE
#define TM_ZONE tm_zone
#else
#undef TM_ZONE
#endif
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
#define TM_GMTOFF tm_gmtoff
#else
#undef TM_GMTOFF
#endif
/*
* The following macro is used to remove const cast-away warnings
* from gcc -Wcast-qual; it should be used with caution because it
* can hide valid errors; in particular most valid uses are in
* situations where the API requires it, not to cast away string
* constants. We don't use *intptr_t on purpose here and we are
* explicit about unsigned long so that we don't have additional
* dependencies.
*/
//#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#define __UNCONST(a) ((void *)(a))
static const unsigned char *conv_num(const unsigned char *, int *, unsigned, unsigned);
static const unsigned char *find_string(const unsigned char *, int *, const char * const *,
const char * const *, int);
#define _TIME_LOCALE(loc) \
((_TimeLocale *)((loc)->part_impl[(size_t)LC_TIME]))
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
#define TM_WEDNESDAY 3
#define TM_THURSDAY 4
#define TM_FRIDAY 5
#define TM_SATURDAY 6
#define TM_JANUARY 0
#define TM_FEBRUARY 1
#define TM_MARCH 2
#define TM_APRIL 3
#define TM_MAY 4
#define TM_JUNE 5
#define TM_JULY 6
#define TM_AUGUST 7
#define TM_SEPTEMBER 8
#define TM_OCTOBER 9
#define TM_NOVEMBER 10
#define TM_DECEMBER 11
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
/*
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
** isleap(y) == isleap(y % 400)
** and so
** isleap(a + b) == isleap((a + b) % 400)
** or
** isleap(a + b) == isleap(a % 400 + b % 400)
** This is true even if % means modulo rather than Fortran remainder
** (which is allowed by C89 but not C99).
** We use this to avoid addition overflow problems.
*/
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
/*
* We do not implement alternate representations. However, we always
@ -79,7 +139,9 @@ static const unsigned char *find_string(const unsigned char *, int *, const char
#define HAVE_YEAR(s) (s & S_YEAR)
#define HAVE_HOUR(s) (s & S_HOUR)
#ifdef TM_ZONE
static char utc[] = { "UTC" };
#endif
/* RFC-822/RFC-2822 */
static const char * const nast[5] = {
"EST", "CST", "MST", "PST", "\0\0\0"
@ -88,6 +150,27 @@ static const char * const nadt[5] = {
"EDT", "CDT", "MDT", "PDT", "\0\0\0"
};
static const char * const cloc_am_pm[] = {"AM", "PM", NULL};
static const char * const cloc_abday[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
};
static const char * const cloc_day[] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thusday", "Friday",
"Saturday", NULL
};
static const char * const cloc_abmon[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec", NULL
};
static const char * const cloc_mon[] = {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December", NULL
};
/*
* Table to determine the ordinal date for the start of a month.
* Ref: http://en.wikipedia.org/wiki/ISO_week_date
@ -115,46 +198,8 @@ first_wday_of(int yr)
#define delim(p) ((p) == '\0' || g_ascii_isspace((unsigned char)(p)))
static int
fromzone(const unsigned char **bp, struct tm *tm, int mandatory)
{
timezone_t tz;
char buf[512], *p;
const unsigned char *rp;
for (p = buf, rp = *bp; !delim(*rp) && p < &buf[sizeof(buf) - 1]; rp++)
*p++ = *rp;
*p = '\0';
if (mandatory)
*bp = rp;
if (!g_ascii_isalnum((unsigned char)*buf))
return 0;
tz = tzalloc(buf);
if (tz == NULL)
return 0;
*bp = rp;
tm->tm_isdst = 0; /* XXX */
#ifdef TM_GMTOFF
tm->TM_GMTOFF = tzgetgmtoff(tz, tm->tm_isdst);
#endif
#ifdef TM_ZONE
// Can't use tzgetname() here because we are going to free()
tm->TM_ZONE = NULL; /* XXX */
#endif
tzfree(tz);
return 1;
}
char *
strptime(const char *buf, const char *fmt, struct tm *tm)
{
return strptime_l(buf, fmt, tm, _current_locale());
}
char *
strptime_l(const char *buf, const char *fmt, struct tm *tm, locale_t loc)
ws_strptime(const char *buf, const char *fmt, struct tm *tm)
{
unsigned char c;
const unsigned char *bp, *ep, *zname;
@ -206,7 +251,7 @@ literal:
* "Complex" conversion rules, implemented through recursion.
*/
case 'c': /* Date and time, using the locale's format. */
new_fmt = _TIME_LOCALE(loc)->d_t_fmt;
new_fmt = "%a %b %e %H:%M:%S %Y";
state |= S_WDAY | S_MON | S_MDAY | S_YEAR;
goto recurse;
@ -228,7 +273,7 @@ literal:
goto recurse;
case 'r': /* The time in 12-hour clock representation. */
new_fmt = _TIME_LOCALE(loc)->t_fmt_ampm;
new_fmt = "%I:%M:%S %p";
LEGAL_ALT(0);
goto recurse;
@ -238,14 +283,14 @@ literal:
goto recurse;
case 'X': /* The time, using the locale's format. */
new_fmt = _TIME_LOCALE(loc)->t_fmt;
new_fmt = "%H:%M:%S";
goto recurse;
case 'x': /* The date, using the locale's format. */
new_fmt = _TIME_LOCALE(loc)->d_fmt;
new_fmt = "%m/%d/%y";
state |= S_MON | S_MDAY | S_YEAR;
recurse:
bp = (const unsigned char *)strptime((const char *)bp,
bp = (const unsigned char *)ws_strptime((const char *)bp,
new_fmt, tm);
LEGAL_ALT(ALT_E);
continue;
@ -255,8 +300,7 @@ literal:
*/
case 'A': /* The day of week, using the locale's form. */
case 'a':
bp = find_string(bp, &tm->tm_wday,
_TIME_LOCALE(loc)->day, _TIME_LOCALE(loc)->abday, 7);
bp = find_string(bp, &tm->tm_wday, cloc_day, cloc_abday, 7);
LEGAL_ALT(0);
state |= S_WDAY;
continue;
@ -264,9 +308,7 @@ literal:
case 'B': /* The month, using the locale's form. */
case 'b':
case 'h':
bp = find_string(bp, &tm->tm_mon,
_TIME_LOCALE(loc)->mon, _TIME_LOCALE(loc)->abmon,
12);
bp = find_string(bp, &tm->tm_mon, cloc_mon, cloc_abmon, 12);
LEGAL_ALT(0);
state |= S_MON;
continue;
@ -333,7 +375,7 @@ literal:
continue;
case 'p': /* The locale's equivalent of AM/PM. */
bp = find_string(bp, &i, _TIME_LOCALE(loc)->am_pm,
bp = find_string(bp, &i, cloc_am_pm,
NULL, 2);
if (HAVE_HOUR(state) && tm->tm_hour > 11)
return NULL;
@ -371,7 +413,7 @@ literal:
continue;
}
if (localtime_r(&sse, tm) == NULL)
if (ws_localtime_r(&sse, tm) == NULL)
bp = NULL;
else
state |= S_YDAY | S_WDAY |
@ -548,11 +590,7 @@ namedzone:
/*
* From our 3 letter hard-coded table
* XXX: Can be removed, handled by tzload()
*/
if (delim(bp[0]) || delim(bp[1]) ||
delim(bp[2]) || !delim(bp[3]))
goto loadzone;
ep = find_string(bp, &i, nast, NULL, 4);
if (ep != NULL) {
#ifdef TM_GMTOFF
@ -593,12 +631,6 @@ namedzone:
bp = ep;
continue;
}
loadzone:
/*
* The hard way, load the zone!
*/
if (fromzone(&bp, tm, mandatory))
continue;
goto out;
}
offs = 0;

31
wsutil/ws_strptime.h Normal file
View File

@ -0,0 +1,31 @@
/** @file
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __WS_STRPTIME_H__
#define __WS_STRPTIME_H__
#include <wireshark.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* This is the NetBSD strptime(), modified to always use the "C" locale.
*/
WS_DLL_PUBLIC
char *
ws_strptime(const char *buf, const char *format, struct tm *tm);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __WS_STRPTIME_H__ */