From b4ca58d9a89c1656ac4eede71855496791cc30cc Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Fri, 5 Aug 2016 20:16:09 -0400 Subject: [PATCH] Revert "Remove support for using system() now other means proven." This reverts commit ebf3b0776ab8d68ca9b3f4f02415092bc8935d75. --- test/tz_test/validate.cpp | 4 +- tz.cpp | 127 ++++++++++++++++++++++++++++++-------- 2 files changed, 103 insertions(+), 28 deletions(-) diff --git a/test/tz_test/validate.cpp b/test/tz_test/validate.cpp index 795fc8a..19de113 100644 --- a/test/tz_test/validate.cpp +++ b/test/tz_test/validate.cpp @@ -90,9 +90,9 @@ tzmain() auto& db = get_tzdb(); std::vector names; names.reserve(db.zones.size() + db.links.size()); - for (const auto& zone : db.zones) + for (auto& zone : db.zones) names.push_back(zone.name()); - for (const auto& link : db.links) + for (auto& link : db.links) names.push_back(link.name()); std::sort(names.begin(), names.end()); std::cout << db.version << "\n\n"; diff --git a/tz.cpp b/tz.cpp index 640028d..9fc0d82 100644 --- a/tz.cpp +++ b/tz.cpp @@ -85,7 +85,6 @@ #include #include #include -#include #include #ifdef _WIN32 @@ -107,12 +106,14 @@ #else // !WIN32 # include # include +# if !USE_SHELL_API # include # include # include # include # include # include +# endif //!USE_SHELL_API #endif // !WIN32 #if HAS_REMOTE_API @@ -154,6 +155,14 @@ get_known_folder(const GUID& folderid) return folder; } +// Usually something like "c:\Program Files". +static +std::string +get_program_folder() +{ + return get_known_folder(FOLDERID_ProgramFiles); +} + // Usually something like "c:\Users\username\Downloads". static std::string @@ -208,7 +217,7 @@ get_download_gz_file(const std::string& version) return file; } -static const std::array files +static const std::vector files = { "africa", "antarctica", "asia", "australasia", "backward", "etcetera", "europe", "pacificnew", "northamerica", "southamerica", "systemv", "leapseconds" @@ -425,6 +434,8 @@ load_timezone_mappings_from_xml_file(const std::string& input_path) // 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[] = { "& eqr, const Rule* prev_rule = nullptr; while (r != nullptr) { - bool found = false; + bool found; switch (r->mdt().zone()) { case tz::utc: @@ -1809,7 +1820,6 @@ time_zone::adjust_infos(const std::vector& rules) { using namespace std::chrono; using string = std::string; - in.clear(); in.str(z.u.rule_); auto tmp = duration_cast(parse_signed_time(in)); #if !defined(_MSC_VER) || (_MSC_VER >= 1900) @@ -2279,21 +2289,35 @@ remote_download(const std::string& version) auto mapping_file = get_download_mapping_file(version); result = download_to_file("http://unicode.org/repos/cldr/trunk/common/" "supplemental/windowsZones.xml", - mapping_file, download_file_options::text); + mapping_file, download_file_options::text); } #endif return result; } +// TODO! Using system() create a process and a console window. +// This is useful to see what errors may occur but is slow and distracting. +// Consider implementing this functionality more directly, such as +// using _mkdir and CreateProcess etc. +// But use the current means now as matches Unix implementations and while +// in proof of concept / testing phase. // TODO! Use eventually. static bool remove_folder_and_subfolders(const std::string& folder) { #ifdef _WIN32 +# if USE_SHELL_API + // Delete the folder contents by deleting the folder. + std::string cmd = "rd /s /q \""; + cmd += folder; + cmd += '\"'; + return std::system(cmd.c_str()) == EXIT_SUCCESS; +# else // !USE_SHELL_API // Create a buffer containing the path to delete. It must be terminated // by two nuls. Who designs these API's... - std::vector from(folder.begin(), folder.end()); + std::vector from; + from.assign(folder.begin(), folder.end()); from.push_back('\0'); from.push_back('\0'); SHFILEOPSTRUCT fo{}; // Zero initialize. @@ -2304,7 +2328,11 @@ remove_folder_and_subfolders(const std::string& folder) if (ret == 0 && !fo.fAnyOperationsAborted) return true; return false; +# endif // !USE_SHELL_API #else // !WIN32 +# if USE_SHELL_API + return std::system(("rm -R " + folder).c_str()) == EXIT_SUCCESS; +# else // !USE_SHELL_API struct dir_deleter { dir_deleter() {} void operator()(DIR* d) const @@ -2349,6 +2377,7 @@ remove_folder_and_subfolders(const std::string& folder) r = rmdir(folder.c_str()) == 0; return r; +# endif // !USE_SHELL_API #endif // !WIN32 } @@ -2357,9 +2386,21 @@ bool make_directory(const std::string& folder) { #ifdef _WIN32 +# if USE_SHELL_API + // Re-create the folder. + std::string cmd = "mkdir \""; + cmd += folder; + cmd += '\"'; + return std::system(cmd.c_str()) == EXIT_SUCCESS; +# else // !USE_SHELL_API return _mkdir(folder.c_str()) == 0; +# endif // !USE_SHELL_API #else // !WIN32 +# if USE_SHELL_API + return std::system(("mkdir " + folder).c_str()) == EXIT_SUCCESS; +# else // !USE_SHELL_API return mkdir(folder.c_str(), 0777) == 0; +# endif // !USE_SHELL_API #endif } @@ -2368,9 +2409,20 @@ bool delete_file(const std::string& file) { #ifdef _WIN32 +# if USE_SHELL_API + std::string cmd = "del \""; + cmd += file; + cmd += '\"'; + return std::system(cmd.c_str()) == 0; +# else // !USE_SHELL_API return _unlink(file.c_str()) == 0; +# endif // !USE_SHELL_API #else // !WIN32 +# if USE_SHELL_API + return std::system(("rm " + file).c_str()) == EXIT_SUCCESS; +# else // !USE_SHELL_API return unlink(file.c_str()) == 0; +# endif // !USE_SHELL_API #endif // !WIN32 } @@ -2381,9 +2433,22 @@ bool move_file(const std::string& from, const std::string& to) { #ifdef _WIN32 +# if USE_SHELL_API + std::string cmd = "move \""; + cmd += from; + cmd += "\" \""; + cmd += to; + cmd += '\"'; + return std::system(cmd.c_str()) == EXIT_SUCCESS; +# else // !USE_SHELL_API return !!::MoveFile(from.c_str(), to.c_str()); +# endif // !USE_SHELL_API #else // !WIN32 +# if USE_SHELL_API + return std::system(("mv " + from + " " + to).c_str()) == EXIT_SUCCESS; +# else return rename(from, to) == 0); +# endif #endif // !WIN32 } @@ -2391,14 +2456,6 @@ move_file(const std::string& from, const std::string& to) #ifdef _WIN32 -// Usually something like "c:\Program Files". -static -std::string -get_program_folder() -{ - return get_known_folder(FOLDERID_ProgramFiles); -} - // Note folder can and usually does contain spaces. static std::string @@ -2431,12 +2488,13 @@ get_unzip_program() } } } - path = get_program_folder(); + path += get_program_folder(); path += folder_delimiter; path += "7-Zip\\7z.exe"; return path; } +#if !USE_SHELL_API static int run_program(const std::string& command) @@ -2464,6 +2522,7 @@ run_program(const std::string& command) } return EXIT_FAILURE; } +#endif // !USE_SHELL_API static std::string @@ -2498,8 +2557,18 @@ extract_gz_file(const std::string& version, const std::string& gz_file, cmd += dest_folder; cmd += '\"'; +#if USE_SHELL_API + // When using shelling out with std::system() extra quotes are required around the + // whole command. It's weird but neccessary it seems, see: + // http://stackoverflow.com/q/27975969/576911 + + cmd = "\"" + cmd + "\""; + if (std::system(cmd.c_str()) == EXIT_SUCCESS) + unzip_result = true; +#else // !USE_SHELL_API if (run_program(cmd) == EXIT_SUCCESS) unzip_result = true; +#endif // !USE_SHELL_API if (unzip_result) delete_file(gz_file); @@ -2513,8 +2582,15 @@ extract_gz_file(const std::string& version, const std::string& gz_file, cmd += "\" -o\""; cmd += install; cmd += '\"'; +#if USE_SHELL_API + cmd = "\"" + cmd + "\""; + if (std::system(cmd.c_str()) == EXIT_SUCCESS) + unzip_result = true; +#else // !USE_SHELL_API if (run_program(cmd) == EXIT_SUCCESS) unzip_result = true; +#endif // !USE_SHELL_API + if (unzip_result) delete_file(tar_file); @@ -2523,6 +2599,7 @@ extract_gz_file(const std::string& version, const std::string& gz_file, #else // !_WIN32 +#if !USE_SHELL_API static int run_program(const char* prog, const char*const args[]) @@ -2552,6 +2629,7 @@ run_program(const char* prog, const char*const args[]) } else // We are in the child process. Start the program the parent wants to run. { + if (execv(prog, const_cast(args)) == -1) // Does not return. { perror("unreachable 0\n"); @@ -2565,17 +2643,22 @@ run_program(const char* prog, const char*const args[]) exit(EXIT_FAILURE); return EXIT_FAILURE; } +#endif // !USE_SHELL_API static bool extract_gz_file(const std::string&, const std::string& gz_file, const std::string&) { +#if USE_SHELL_API + bool unzipped = std::system(("tar -xzf " + gz_file + " -C " + install).c_str()) == EXIT_SUCCESS; +#else // !USE_SHELL_API const char prog[] = {"/usr/bin/tar"}; const char*const args[] = { prog, "-xzf", gz_file.c_str(), "-C", install.c_str(), nullptr }; bool unzipped = (run_program(prog, args) == EXIT_SUCCESS); +#endif // !USE_SHELL_API if (unzipped) { delete_file(gz_file); @@ -2639,6 +2722,8 @@ init_tzdb() { using namespace date; const std::string path = install + folder_delimiter; + std::string line; + bool continue_zone = false; TZ_DB db; #if AUTO_DOWNLOAD @@ -2690,19 +2775,9 @@ init_tzdb() db.version = get_version(path); #endif // !AUTO_DOWNLOAD - std::string line; - bool continue_zone = false; for (const auto& filename : files) { - std::string infile_name{path + filename}; - std::ifstream infile(infile_name); - if (!infile) - { - std::string msg = "Error opening time zone data file \""; - msg += infile_name; - msg += "\"."; - throw std::runtime_error(msg); - } + std::ifstream infile(path + filename); while (infile) { std::getline(infile, line);