aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Warta <[email protected]>2015-07-27 13:04:56 +0200
committerSimon Warta <[email protected]>2015-07-27 13:04:56 +0200
commit4aa3efdf15c9d9746d31e6e57d5137152f5fd29f (patch)
treeaaa398b0f162e7a6cf2d340d0aedb63d351fc69d /src
parent519cb1d28e082524797905016cc338a846f88011 (diff)
parent18e055b6dcb5688a8c669cdbc54d53541681a21e (diff)
Merge pull request #205 from webmaster128/mktime
Add timegm() fallbacks using mktime+TZ or boost
Diffstat (limited to 'src')
-rw-r--r--src/build-data/os/cygwin.txt1
-rw-r--r--src/build-data/os/darwin.txt1
-rw-r--r--src/build-data/os/freebsd.txt1
-rw-r--r--src/build-data/os/linux.txt1
-rw-r--r--src/build-data/os/mingw.txt1
-rw-r--r--src/build-data/os/netbsd.txt1
-rw-r--r--src/build-data/os/openbsd.txt1
-rw-r--r--src/build-data/os/windows.txt1
-rw-r--r--src/lib/utils/calendar.cpp99
-rw-r--r--src/lib/vendor/boost/info.txt1
-rwxr-xr-xsrc/scripts/update_docs.py100
-rw-r--r--src/tests/catchy/test_utils.cpp41
12 files changed, 238 insertions, 11 deletions
diff --git a/src/build-data/os/cygwin.txt b/src/build-data/os/cygwin.txt
index eb5835a6f..be67e2607 100644
--- a/src/build-data/os/cygwin.txt
+++ b/src/build-data/os/cygwin.txt
@@ -13,4 +13,5 @@ doc_dir docs
<target_features>
gettimeofday
getsid
+timegm
</target_features>
diff --git a/src/build-data/os/darwin.txt b/src/build-data/os/darwin.txt
index f5f2589fb..3a13b34e4 100644
--- a/src/build-data/os/darwin.txt
+++ b/src/build-data/os/darwin.txt
@@ -15,6 +15,7 @@ gmtime_r
memset_s
readdir
getsid
+timegm
</target_features>
<aliases>
diff --git a/src/build-data/os/freebsd.txt b/src/build-data/os/freebsd.txt
index 346145785..32767cb1f 100644
--- a/src/build-data/os/freebsd.txt
+++ b/src/build-data/os/freebsd.txt
@@ -8,4 +8,5 @@ gmtime_r
dlopen
readdir
getsid
+timegm
</target_features>
diff --git a/src/build-data/os/linux.txt b/src/build-data/os/linux.txt
index cb78c33ff..48c3bf318 100644
--- a/src/build-data/os/linux.txt
+++ b/src/build-data/os/linux.txt
@@ -8,6 +8,7 @@ gmtime_r
dlopen
readdir
getsid
+timegm
</target_features>
<aliases>
diff --git a/src/build-data/os/mingw.txt b/src/build-data/os/mingw.txt
index 4f3e7f08b..cc98b11e6 100644
--- a/src/build-data/os/mingw.txt
+++ b/src/build-data/os/mingw.txt
@@ -23,6 +23,7 @@ mingw32
<target_features>
cryptgenrandom
loadlibrary
+mkgmtime
win32_virtual_lock
win32_get_systemtime
</target_features>
diff --git a/src/build-data/os/netbsd.txt b/src/build-data/os/netbsd.txt
index 346145785..32767cb1f 100644
--- a/src/build-data/os/netbsd.txt
+++ b/src/build-data/os/netbsd.txt
@@ -8,4 +8,5 @@ gmtime_r
dlopen
readdir
getsid
+timegm
</target_features>
diff --git a/src/build-data/os/openbsd.txt b/src/build-data/os/openbsd.txt
index 5df133c8e..510a7accd 100644
--- a/src/build-data/os/openbsd.txt
+++ b/src/build-data/os/openbsd.txt
@@ -7,4 +7,5 @@ posix_mlock
gmtime_r
dlopen
readdir
+timegm
</target_features>
diff --git a/src/build-data/os/windows.txt b/src/build-data/os/windows.txt
index c34f2e7ab..fd74fe817 100644
--- a/src/build-data/os/windows.txt
+++ b/src/build-data/os/windows.txt
@@ -15,6 +15,7 @@ install_cmd_exec "copy"
cryptgenrandom
gmtime_s
loadlibrary
+mkgmtime
query_perf_counter
virtual_lock
rtlsecurezeromemory
diff --git a/src/lib/utils/calendar.cpp b/src/lib/utils/calendar.cpp
index 0ef8be356..f071a7328 100644
--- a/src/lib/utils/calendar.cpp
+++ b/src/lib/utils/calendar.cpp
@@ -11,6 +11,11 @@
#include <ctime>
#include <sstream>
#include <iomanip>
+#include <mutex>
+
+#if defined(BOTAN_HAS_BOOST_DATETIME)
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#endif
namespace Botan {
@@ -26,7 +31,7 @@ std::tm do_gmtime(std::time_t time_val)
gmtime_r(&time_val, &tm); // Unix/SUSv2
#else
std::tm* tm_p = std::gmtime(&time_val);
- if (tm_p == 0)
+ if (tm_p == nullptr)
throw Encoding_Error("time_t_to_tm could not convert");
tm = *tm_p;
#endif
@@ -34,11 +39,83 @@ std::tm do_gmtime(std::time_t time_val)
return tm;
}
+#if !defined(BOTAN_TARGET_OS_HAS_TIMEGM) && !defined(BOTAN_TARGET_OS_HAS_MKGMTIME)
+
+#if defined(BOTAN_HAS_BOOST_DATETIME)
+
+std::time_t boost_timegm(std::tm *tm)
+ {
+ const int sec = tm->tm_sec;
+ const int min = tm->tm_min;
+ const int hour = tm->tm_hour;
+ const int day = tm->tm_mday;
+ const int mon = tm->tm_mon + 1;
+ const int year = tm->tm_year + 1900;
+
+ std::time_t out;
+
+ {
+ using namespace boost::posix_time;
+ using namespace boost::gregorian;
+ const auto epoch = ptime(date(1970, 01, 01));
+ const auto time = ptime(date(year, mon, day),
+ hours(hour) + minutes(min) + seconds(sec));
+ const time_duration diff(time - epoch);
+ out = diff.ticks() / diff.ticks_per_second();
+ }
+
+ return out;
+ }
+
+#else
+
+#pragma message "Caution! A fallback version of timegm() is used which is not thread-safe"
+
+std::mutex ENV_TZ;
+
+std::time_t fallback_timegm(std::tm *tm)
+ {
+ std::time_t out;
+ std::string tz_backup;
+
+ ENV_TZ.lock();
+
+ // Store current value of env variable TZ
+ const char* tz_env_pointer = ::getenv("TZ");
+ if (tz_env_pointer != nullptr)
+ tz_backup = std::string(tz_env_pointer);
+
+ // Clear value of TZ
+ ::setenv("TZ", "", 1);
+ ::tzset();
+
+ out = ::mktime(tm);
+
+ // Restore TZ
+ if (!tz_backup.empty())
+ {
+ // setenv makes a copy of the second argument
+ ::setenv("TZ", tz_backup.data(), 1);
+ }
+ else
+ {
+ ::unsetenv("TZ");
+ }
+ ::tzset();
+
+ ENV_TZ.unlock();
+
+ return out;
+}
+#endif // BOTAN_HAS_BOOST_DATETIME
+
+#endif
+
}
std::chrono::system_clock::time_point calendar_point::to_std_timepoint()
{
- if (year < 1900)
+ if (year < 1970)
throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years before 1990.");
// 32 bit time_t ends at January 19, 2038
@@ -48,7 +125,9 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint()
if (year > 2037)
throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2037.");
+ // std::tm: struct without any timezone information
std::tm tm;
+ tm.tm_isdst = -1; // i.e. no DST information available
tm.tm_sec = seconds;
tm.tm_min = minutes;
tm.tm_hour = hour;
@@ -56,12 +135,20 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint()
tm.tm_mon = month - 1;
tm.tm_year = year - 1900;
- // Convert std::tm to std::time_t
+ // Define a function alias `botan_timegm`
+ #if defined(BOTAN_TARGET_OS_HAS_TIMEGM)
+ std::time_t (&botan_timegm)(std::tm *tm) = timegm;
+ #elif defined(BOTAN_TARGET_OS_HAS_MKGMTIME)
// http://stackoverflow.com/questions/16647819/timegm-cross-platform
- #if defined(BOTAN_TARGET_OS_IS_WINDOWS)
- #define timegm _mkgmtime
+ std::time_t (&botan_timegm)(std::tm *tm) = _mkgmtime;
+ #elif defined(BOTAN_HAS_BOOST_DATETIME)
+ std::time_t (&botan_timegm)(std::tm *tm) = boost_timegm;
+ #else
+ std::time_t (&botan_timegm)(std::tm *tm) = fallback_timegm;
#endif
- std::time_t tt = timegm(&tm);
+
+ // Convert std::tm to std::time_t
+ std::time_t tt = botan_timegm(&tm);
if (tt == -1)
throw Invalid_Argument("calendar_point couldn't be converted: " + to_string());
diff --git a/src/lib/vendor/boost/info.txt b/src/lib/vendor/boost/info.txt
index c335dcd74..8748c0bf1 100644
--- a/src/lib/vendor/boost/info.txt
+++ b/src/lib/vendor/boost/info.txt
@@ -1,5 +1,6 @@
define BOOST_FILESYSTEM 20131228
define BOOST_ASIO 20131228
+define BOOST_DATETIME 20150720
load_on vendor
diff --git a/src/scripts/update_docs.py b/src/scripts/update_docs.py
new file mode 100755
index 000000000..03b9dd67b
--- /dev/null
+++ b/src/scripts/update_docs.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+"""
+A script to automatically write docs to /docs. Currently it generates
+os.rst, a feature table of OS features.
+
+Requires Python 3.
+
+(C) 2015 Simon Warta (Kullo GmbH)
+
+Botan is released under the Simplified BSD License (see license.txt)
+"""
+
+# global
+import argparse
+import glob
+import os
+import sys
+
+# Assume this script is in botan/src/scripts
+botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..")
+
+# locale
+sys.path.append(botan_root)
+from configure import OsInfo
+
+parser = argparse.ArgumentParser(description="")
+parser.add_argument('--verbose', dest='verbose', action='store_const',
+ const=True, default=False,
+ help='Verbose output (default: false)')
+args = parser.parse_args()
+
+def update_os():
+ PAGE_TITLE="Botan OS information"
+ TABLE_TITLE="OS Features"
+
+ files = []
+ files += glob.glob(botan_root + '/src/build-data/os/*.txt')
+ files.sort()
+
+ if len(files) == 0:
+ print("No info.txt files found.")
+ sys.exit(1)
+
+ f1 = open(os.path.join(botan_root, 'doc', 'os.rst'), 'w+')
+
+ all_features = set()
+ oss = {}
+
+ for filename in files:
+ o = OsInfo(filename)
+ oss[o.basename] = o
+ all_features |= set(o.target_features)
+ if args.verbose:
+ print(o.basename)
+ print(o.target_features)
+
+ featurelist = list(all_features)
+ featurelist.sort()
+ oslist = list(oss.keys())
+ oslist.sort()
+
+ if args.verbose:
+ print(featurelist)
+
+ print(PAGE_TITLE, file=f1)
+ print("========================================", file=f1)
+ print("", file=f1)
+
+ print(TABLE_TITLE, file=f1)
+ print("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", file=f1)
+ print("", file=f1)
+
+ print("A summary of OS features as defined in ``src/build-data/os``.", file=f1)
+ print("", file=f1)
+
+ print("::", file=f1)
+ print("", file=f1)
+ for o in oslist:
+ print(" %s: %s" % (o[0:1], o), file=f1)
+ print("", file=f1)
+
+ print('.. csv-table::', file=f1)
+ print(' :header: "Feature", "' + '", "'.join([o[0:1] for o in oslist]) + '"', file=f1)
+ print('', file=f1)
+
+ for f in featurelist:
+ line = ' "' + f + '"'
+ for o in oslist:
+ line += ', "'
+ line += 'X' if f in oss[o].target_features else ' '
+ line += '"'
+ print(line, file=f1)
+ print("", file=f1)
+ print(".. note::", file=f1)
+ print(" This file is auto generated by ``src/scripts/%s``. Dont modify it manually."
+ % os.path.basename(sys.argv[0]), file=f1)
+
+if __name__ == '__main__':
+ update_os()
diff --git a/src/tests/catchy/test_utils.cpp b/src/tests/catchy/test_utils.cpp
index ad4191e3c..702d82f9c 100644
--- a/src/tests/catchy/test_utils.cpp
+++ b/src/tests/catchy/test_utils.cpp
@@ -100,6 +100,7 @@ TEST_CASE("calendar_point constructor works", "[utils]")
TEST_CASE("calendar_point to stl timepoint and back", "[utils]")
{
+ SECTION("default test")
{
auto in = calendar_point(1988, 04, 23, 14, 37, 28);
auto out = calendar_value(in.to_std_timepoint());
@@ -111,7 +112,20 @@ TEST_CASE("calendar_point to stl timepoint and back", "[utils]")
CHECK(( out.seconds == 28 ));
}
- SECTION("latest possible time point")
+ // _mkgmtime on Windows does not work for dates before 1970
+ SECTION("first possible time point")
+ {
+ auto in = calendar_point(1970, 01, 01, 00, 00, 00);
+ auto out = calendar_value(in.to_std_timepoint());
+ CHECK(( out.year == 1970 ));
+ CHECK(( out.month == 01 ));
+ CHECK(( out.day == 01 ));
+ CHECK(( out.hour == 00 ));
+ CHECK(( out.minutes == 00 ));
+ CHECK(( out.seconds == 00 ));
+ }
+
+ SECTION("latest possible time point")
{
auto in = calendar_point(2037, 12, 31, 23, 59, 59);
auto out = calendar_value(in.to_std_timepoint());
@@ -123,13 +137,30 @@ TEST_CASE("calendar_point to stl timepoint and back", "[utils]")
CHECK(( out.seconds == 59 ));
}
- SECTION("year too early")
+ SECTION("year too early")
{
- auto in = calendar_point(1800, 01, 01, 0, 0, 0);
- CHECK_THROWS( in.to_std_timepoint() );
+ {
+ auto in = calendar_point(1800, 01, 01, 0, 0, 0);
+ CHECK_THROWS( in.to_std_timepoint() );
+ }
+
+ {
+ auto in = calendar_point(1899, 12, 31, 23, 59, 59);
+ CHECK_THROWS( in.to_std_timepoint() );
+ }
+
+ {
+ auto in = calendar_point(1969, 12, 31, 23, 59, 58); // time_t = -2
+ CHECK_THROWS( in.to_std_timepoint() );
+ }
+
+ {
+ auto in = calendar_point(1969, 12, 31, 23, 59, 59); // time_t = -1
+ CHECK_THROWS( in.to_std_timepoint() );
+ }
}
- SECTION("year too late")
+ SECTION("year too late")
{
auto in = calendar_point(2038, 01, 01, 0, 0, 0);
CHECK_THROWS( in.to_std_timepoint() );