diff --git a/tz.cpp b/tz.cpp index be3df40..64febcc 100644 --- a/tz.cpp +++ b/tz.cpp @@ -30,58 +30,58 @@ // We did not mean to shout. #ifdef _WIN32 -// Windows.h will be included directly and indirectly (e.g. by curl). -// We need to define these macros to prevent Windows.h bringing in -// more than we need and do it early so Windows.h doesn't get included -// without these macros having been defined. -// min/max macros interfere with the C++ versions. -#ifndef NOMINMAX -#define NOMINMAX -#endif -// We don't need all that Windows has to offer. -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN + // Windows.h will be included directly and indirectly (e.g. by curl). + // We need to define these macros to prevent Windows.h bringing in + // more than we need and do it early so Windows.h doesn't get included + // without these macros having been defined. + // min/max macros interfere with the C++ versions. +# ifndef NOMINMAX +# define NOMINMAX +# endif + // We don't need all that Windows has to offer. +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif + + // for wcstombs +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif + + // None of this happens with the MS SDK (at least VS14 which I tested), but: + // Compiling with mingw, we get "error: 'KF_FLAG_DEFAULT' was not declared in this scope." + // and error: 'SHGetKnownFolderPath' was not declared in this scope.". + // It seems when using mingw NTDDI_VERSION is undefined and that + // causes KNOWN_FOLDER_FLAG and the KF_ flags to not get defined. + // So we must define NTDDI_VERSION to get those flags on mingw. + // The docs say though here: + // https://msdn.microsoft.com/en-nz/library/windows/desktop/aa383745(v=vs.85).aspx + // that "If you define NTDDI_VERSION, you must also define _WIN32_WINNT." + // So we declare we require Vista or greater. +# ifdef __MINGW32__ + +# ifndef NTDDI_VERSION +# define NTDDI_VERSION 0x06000000 +# define _WIN32_WINNT _WIN32_WINNT_VISTA +# elif NTDDI_VERSION < 0x06000000 +# warning "If this fails to compile NTDDI_VERSION may be to low. See comments above." +# endif + // But once we define the values above we then get this linker error: + // "tz.cpp:(.rdata$.refptr.FOLDERID_Downloads[.refptr.FOLDERID_Downloads]+0x0): " + // "undefined reference to `FOLDERID_Downloads'" + // which #include cures see: + // https://support.microsoft.com/en-us/kb/130869 +# include + // But with included, the error moves on to: + // error: 'FOLDERID_Downloads' was not declared in this scope + // Which #include cures. +# include + +# endif // __MINGW32__ + +# include #endif // _WIN32 -// for wcstombs -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -// None of this happens with the MS SDK (at least VS14 which I tested), but: -// Compiling with mingw, we get "error: 'KF_FLAG_DEFAULT' was not declared in this scope." -// and error: 'SHGetKnownFolderPath' was not declared in this scope.". -// It seems when using mingw NTDDI_VERSION is undefined and that -// causes KNOWN_FOLDER_FLAG and the KF_ flags to not get defined. -// So we must define NTDDI_VERSION to get those flags on mingw. -// The docs say though here: -// https://msdn.microsoft.com/en-nz/library/windows/desktop/aa383745(v=vs.85).aspx -// that "If you define NTDDI_VERSION, you must also define _WIN32_WINNT." -// So we declare we require Vista or greater. -#ifdef __MINGW32__ - -#ifndef NTDDI_VERSION -#define NTDDI_VERSION 0x06000000 -#define _WIN32_WINNT _WIN32_WINNT_VISTA -#elif NTDDI_VERSION < 0x06000000 -#warning "If this fails to compile NTDDI_VERSION may be to low. See comments above." -#endif -// But once we define the values above we then get this linker error: -// "tz.cpp:(.rdata$.refptr.FOLDERID_Downloads[.refptr.FOLDERID_Downloads]+0x0): " -// "undefined reference to `FOLDERID_Downloads'" -// which #include cures see: -// https://support.microsoft.com/en-us/kb/130869 -#include -// But with included, the error moves on to: -// error: 'FOLDERID_Downloads' was not declared in this scope -// Which #include cures. -#include - -#endif // __MINGW32__ - -#include -#endif // _WIN32 - #include "tz_private.h" #include "ios.h" @@ -106,7 +106,8 @@ # include // _unlink etc. # if defined(__clang__) - struct IUnknown; // fix for issue with static_cast<> in objbase.h (see https://github.com/philsquared/Catch/issues/690) + struct IUnknown; // fix for issue with static_cast<> in objbase.h + // (see https://github.com/philsquared/Catch/issues/690) # endif # include // CoTaskFree, ShGetKnownFolderPath etc. @@ -114,7 +115,7 @@ # include // _mkdir # include // ShFileOperation etc. # endif // HAS_REMOTE_API -#else // !WIN32 +#else // !_WIN32 # include # include # include @@ -127,30 +128,26 @@ # include # include # endif //!USE_SHELL_API -#endif // !WIN32 +#endif // !_WIN32 #if HAS_REMOTE_API -// Note curl includes windows.h so we must include curl AFTER definitions of things -// that effect windows.h such as NOMINMAX. -#include + // Note curl includes windows.h so we must include curl AFTER definitions of things + // that effect windows.h such as NOMINMAX. +# include #endif #ifdef _WIN32 - static CONSTDATA char folder_delimiter = '\\'; - -#else - +#else // !_WIN32 static CONSTDATA char folder_delimiter = '/'; - -#endif +#endif // !_WIN32 #if defined(__GNUC__) && __GNUC__ < 5 -// GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif + // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif // defined(__GNUC__) && __GNUC__ < 5 #ifdef _WIN32 @@ -210,14 +207,14 @@ expand_path(std::string path) { # if TARGET_OS_IPHONE return date::iOSUtils::get_tzdata_path(); -# else +# else // !TARGET_OS_IPHONE ::wordexp_t w{}; ::wordexp(path.c_str(), &w, 0); assert(w.we_wordc == 1); path = w.we_wordv[0]; ::wordfree(&w); return path; -# endif +# endif // !TARGET_OS_IPHONE } # endif // !INSTALL @@ -248,14 +245,14 @@ access_install() = get_download_folder() + folder_delimiter + "tzdata"; -#else // INSTALL +#else // !INSTALL # define STRINGIZEIMP(x) #x # define STRINGIZE(x) STRINGIZEIMP(x) = STRINGIZE(INSTALL) + std::string(1, folder_delimiter) + "tzdata"; -#endif // INSTALL +#endif // !INSTALL return install; } @@ -304,190 +301,7 @@ struct undocumented {explicit undocumented() = default;}; static_assert(min_year <= max_year, "Configuration error"); #endif -#ifdef TIMEZONE_MAPPING - -namespace // Put types in an anonymous name space. -{ - -const std::string& -get_windows_zones_install() -{ - static const std::string install -#ifndef WINDOWSZONES_INSTALL - = get_install(); -#else -# define STRINGIZEIMP(x) #x -# define STRINGIZE(x) STRINGIZEIMP(x) - = STRINGIZE(WINDOWSZONES_INSTALL); -#endif - return install; -} - -} // anonymous namespace - -static -std::string -get_download_mapping_file(const std::string& version) -{ - auto file = get_install() + version + "windowsZones.xml"; - return file; -} - -// Parse this XML file: -// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml -// The parsing method is designed to be simple and quick. It is not overly -// forgiving of change but it should diagnose basic format issues. -// See timezone_mapping structure for more info. -static -std::vector -load_timezone_mappings_from_xml_file(const std::string& input_path) -{ - std::size_t line_num = 0; - std::vector mappings; - std::string line; - - std::ifstream is(input_path); - if (!is.is_open()) - { - // We don't emit file exceptions because that's an implementation detail. - std::string msg = "Error opening time zone mapping file \""; - msg += input_path; - msg += "\"."; - throw std::runtime_error(msg); - } - - auto error = [&input_path, &line_num](const char* info) - { - std::string msg = "Error loading time zone mapping file \""; - msg += input_path; - msg += "\" at line "; - msg += std::to_string(line_num); - msg += ": "; - msg += info; - throw std::runtime_error(msg); - }; - // [optional space]a="b" - auto read_attribute = [&line_num, &line, &error] - (const char* name, std::string& value, std::size_t startPos) - ->std::size_t - { - value.clear(); - // Skip leading space before attribute name. - std::size_t spos = line.find_first_not_of(' ', startPos); - if (spos == std::string::npos) - spos = startPos; - // Assume everything up to next = is the attribute name - // and that an = will always delimit that. - std::size_t epos = line.find('=', spos); - if (epos == std::string::npos) - error("Expected \'=\' right after attribute name."); - std::size_t name_len = epos - spos; - // Expect the name we find matches the name we expect. - if (line.compare(spos, name_len, name) != 0) - { - std::string msg; - msg = "Expected attribute name \'"; - msg += name; - msg += "\' around position "; - msg += std::to_string(spos); - msg += " but found something else."; - error(msg.c_str()); - } - ++epos; // Skip the '=' that is after the attribute name. - spos = epos; - if (spos < line.length() && line[spos] == '\"') - ++spos; // Skip the quote that is before the attribute value. - else - { - std::string msg = "Expected '\"' to begin value of attribute \'"; - msg += name; - msg += "\'."; - error(msg.c_str()); - } - epos = line.find('\"', spos); - if (epos == std::string::npos) - { - std::string msg = "Expected '\"' to end value of attribute \'"; - msg += name; - msg += "\'."; - error(msg.c_str()); - } - // Extract everything in between the quotes. Note no escaping is done. - std::size_t value_len = epos - spos; - value.assign(line, spos, value_len); - ++epos; // Skip the quote that is after the attribute value; - return epos; - }; - - // Quick but not overly forgiving XML mapping file processing. - bool mapTimezonesOpenTagFound = false; - bool mapTimezonesCloseTagFound = false; - bool mapZoneOpenTagFound = false; - bool mapTZoneCloseTagFound = false; - std::size_t mapZonePos = std::string::npos; - std::size_t mapTimezonesPos = std::string::npos; - CONSTDATA char mapTimeZonesOpeningTag[] = { ""); - mapTimezonesCloseTagFound = (mapTimezonesPos != std::string::npos); - if (!mapTimezonesCloseTagFound) - { - std::size_t commentPos = line.find(" windows tz name mappings - // for this function to work. - // TODO! we should really support TIMEZONE_MAPPINGS=0 on Windows, - // And in this mode we should read the current iana timezone from a file. - // This would allow the TZ library do be used by apps that don't care - // about Windows standard names just iana names. - // This would allow the xml dependency to be dropped and none of - // the name mapping functions would be needed. - throw std::runtime_error("current_zone not implemented."); -#endif // !TIMEZONE_MAPPING } -#else // !WIN32 +#else // !_WIN32 const time_zone* current_zone() @@ -2998,27 +2922,7 @@ current_zone() throw std::runtime_error("Could not get current timezone"); } -#endif // !WIN32 - -#if defined(TZ_TEST) && defined(TIMEZONE_MAPPING) - -const time_zone* -locate_native_zone(const std::string& native_tz_name) -{ - std::string standard_tz_name; - if (!native_to_standard_timezone_name(native_tz_name, standard_tz_name)) - { - std::string msg; - msg = "locate_native_zone() failed: A mapping from the native/Windows Time Zone id \""; - msg += native_tz_name; - msg += "\" was not found in the time zone mapping database."; - throw std::runtime_error(msg); - } - return locate_zone(standard_tz_name); -} - -#endif // TZ_TEST && TIMEZONE_MAPPING - +#endif // !_WIN32 } // namespace date diff --git a/tz.h b/tz.h index 39f8baf..3b1767f 100644 --- a/tz.h +++ b/tz.h @@ -41,16 +41,6 @@ // required. On Windows, the names are never "Standard" so mapping is always required. // Technically any OS may use the mapping process but currently only Windows does use it. -#ifdef _WIN32 -# ifndef TIMEZONE_MAPPING -# define TIMEZONE_MAPPING 1 -# endif -#else -# ifdef TIMEZONE_MAPPING -# error "Timezone mapping is not required or not implemented for this platform." -# endif -#endif - #ifndef LAZY_INIT # define LAZY_INIT 1 #endif @@ -676,7 +666,7 @@ operator>=(const sys_time& x, const leap& y) return !(x < y); } -#ifdef TIMEZONE_MAPPING +#ifdef _WIN32 namespace detail { @@ -712,7 +702,7 @@ struct timezone_mapping } // detail -#endif // TIMEZONE_MAPPING +#endif // _WIN32 struct TZ_DB { @@ -721,8 +711,7 @@ struct TZ_DB std::vector links; std::vector leaps; std::vector rules; -#ifdef TIMEZONE_MAPPING - // TODO! These need some protection. +#ifdef _WIN32 std::vector mappings; #endif @@ -737,7 +726,7 @@ struct TZ_DB , links(std::move(src.links)) , leaps(std::move(src.leaps)) , rules(std::move(src.rules)) -#ifdef TIMEZONE_MAPPING +#ifdef _WIN32 , mappings(std::move(src.mappings)) #endif {} @@ -749,7 +738,7 @@ struct TZ_DB links = std::move(src.links); leaps = std::move(src.leaps); rules = std::move(src.rules); -#ifdef TIMEZONE_MAPPING +#ifdef _WIN32 mappings = std::move(src.mappings); #endif return *this; @@ -771,11 +760,6 @@ DATE_API bool remote_install(const std::string& version); #endif DATE_API const time_zone* locate_zone(const std::string& tz_name); -#ifdef TZ_TEST -# if _WIN32 -DATE_API const time_zone* locate_native_zone(const std::string& native_tz_name); -# endif // _WIN32 -#endif // TZ_TEST DATE_API const time_zone* current_zone(); // zoned_time