forked from HowardHinnant/date
Merge pull request #54 from gmcode/master
mapping file suggested changes.
This commit is contained in:
@ -83,8 +83,8 @@ test_info(const date::time_zone* zone, const date::sys_info& info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
main()
|
tzmain()
|
||||||
{
|
{
|
||||||
using namespace date;
|
using namespace date;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
@ -142,4 +142,19 @@ main()
|
|||||||
}
|
}
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tzmain();
|
||||||
|
}
|
||||||
|
catch(const std::exception& ex)
|
||||||
|
{
|
||||||
|
std::cout << "An exception occured: " << ex.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
106
tz.cpp
106
tz.cpp
@ -50,15 +50,13 @@
|
|||||||
#if TIMEZONE_MAPPING
|
#if TIMEZONE_MAPPING
|
||||||
// Timezone mapping maps native (e.g. Windows) timezone names to the "Standard" names
|
// Timezone mapping maps native (e.g. Windows) timezone names to the "Standard" names
|
||||||
// used by this library.
|
// used by this library.
|
||||||
// The mapping process parses a CSV file of mapping data and uses std::quoted to do that.
|
// The mapping process parses a CSV file of mapping data where each line is of the format:
|
||||||
// Because std::quoted is a C++14 feature found in <iomanip> any platforms using
|
// "other","territory","type"<newline>
|
||||||
// the mapping process require C++14.
|
// e.g. "GMT Standard Time", "001", "Europe/London"
|
||||||
// Windows uses the mapping process so C++14 is required on Windows.
|
// and <newline>
|
||||||
// VS2015 supports std::quoted but there is no -std=c++14 flag required to enable it.
|
// Windows typically uses CRLF, Linux/Unix/Mac OS use LF, and old Mac's use CR.
|
||||||
// MinGW on Windows also requires the mapping process so -std=c++14 is required
|
// On Linux/Mac, no mapping file is required as that is the native format already.
|
||||||
// when using g++ or clang.
|
// C++11 should work but C++14 is preferred even there too
|
||||||
// On Linux/Mac, no mapping / CSV file is required so std::quoted and C++14 isn't needed
|
|
||||||
// and so on these platforms C++11 should work but C++14 is preferred even there too
|
|
||||||
// because the date library in general works better with C++14.
|
// because the date library in general works better with C++14.
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#endif
|
#endif
|
||||||
@ -381,19 +379,30 @@ static const detail::timezone_info* find_native_timezone_by_standard_name(
|
|||||||
static std::vector<detail::timezone_mapping>
|
static std::vector<detail::timezone_mapping>
|
||||||
load_timezone_mappings_from_csv_file(const std::string& input_path)
|
load_timezone_mappings_from_csv_file(const std::string& input_path)
|
||||||
{
|
{
|
||||||
size_t line = 1;
|
size_t line = 0;
|
||||||
std::vector<detail::timezone_mapping> mappings;
|
std::vector<detail::timezone_mapping> mappings;
|
||||||
std::ifstream is(input_path, std::ios_base::in | std::ios_base::binary);
|
std::ifstream is(input_path,
|
||||||
|
#if _WIN32
|
||||||
|
std::ios_base::in // open in text mode on Win32, so getline will eat '\n' and '\r\n'
|
||||||
|
#else
|
||||||
|
std::ios_base::in | std::ios_base::binary
|
||||||
|
#endif
|
||||||
|
);
|
||||||
if (!is.is_open())
|
if (!is.is_open())
|
||||||
{
|
{
|
||||||
// We don't emit file exceptions because that's an implementation detail.
|
// We don't emit file exceptions because that's an implementation detail.
|
||||||
std::string msg = "Error opening time zone mapping file: ";
|
std::string msg = "Error opening time zone mapping file \"";
|
||||||
msg += input_path;
|
msg += input_path;
|
||||||
|
msg += "\".";
|
||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::stringstream sis;
|
||||||
auto error = [&](const char* info)
|
auto error = [&](const char* info)
|
||||||
{
|
{
|
||||||
std::string msg = "Error reading zone mapping file at line ";
|
std::string msg = "Error reading zone mapping file \"";
|
||||||
|
msg += input_path;
|
||||||
|
msg += "\" at line ";
|
||||||
msg += std::to_string(line);
|
msg += std::to_string(line);
|
||||||
msg += ": ";
|
msg += ": ";
|
||||||
msg += info;
|
msg += info;
|
||||||
@ -403,39 +412,68 @@ load_timezone_mappings_from_csv_file(const std::string& input_path)
|
|||||||
auto read_field_delim = [&]()
|
auto read_field_delim = [&]()
|
||||||
{
|
{
|
||||||
char field_delim;
|
char field_delim;
|
||||||
is.read(&field_delim, 1);
|
sis.read(&field_delim, 1);
|
||||||
if (is.gcount() != 1 || field_delim != ',')
|
if (sis.gcount() != 1 || field_delim != ',')
|
||||||
error("delimiter ',' expected");
|
error("delimiter ',' expected.");
|
||||||
};
|
};
|
||||||
std::string copyright;
|
std::string copyright;
|
||||||
for (int i = 0; i < 4; ++i)
|
bool blank = false;
|
||||||
getline(is, copyright);
|
for (;;)
|
||||||
|
{
|
||||||
|
std::getline(is, copyright);
|
||||||
|
++line; // Make sure our line number is in sync with however many copyright lines we have.
|
||||||
|
if (is.eof())
|
||||||
|
break;
|
||||||
|
if (copyright.empty())
|
||||||
|
{
|
||||||
|
--line;
|
||||||
|
blank = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int min_copyright_lines = 3;
|
||||||
|
if (!blank || line < min_copyright_lines)
|
||||||
|
{
|
||||||
|
std::string msg = "Expected at least ";
|
||||||
|
msg += std::to_string(min_copyright_lines);
|
||||||
|
msg += " lines of copyright notice followed by a blank line.";
|
||||||
|
error(msg.c_str());
|
||||||
|
}
|
||||||
|
++line;
|
||||||
|
|
||||||
|
std::string linebuf;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
detail::timezone_mapping zm{};
|
detail::timezone_mapping zm{};
|
||||||
|
std::getline(is, linebuf);
|
||||||
|
// Stop on error or first blank line.
|
||||||
|
// linebuf.size() is the length read but it excludes the length of any line delimiter actually read (e.g. LF/CRLF).
|
||||||
|
// If linebuf.size() is 0 it *might* not mean nothing was read (error) or eof, it could just
|
||||||
|
// indicate only a line delimiter was read. Use is.eof() to distinquish end of file from a blank line.
|
||||||
|
if (linebuf.empty()) // on eof linebuf will be empty.
|
||||||
|
{
|
||||||
|
if (is.eof())
|
||||||
|
break;
|
||||||
|
error("Formatting error. Blank lines not allowed.");
|
||||||
|
}
|
||||||
|
sis.clear();
|
||||||
|
sis.str(linebuf);
|
||||||
|
|
||||||
char ch;
|
char ch;
|
||||||
|
sis.read(&ch, 1);
|
||||||
is.read(&ch, 1);
|
std::getline(sis, zm.other, '\"');
|
||||||
if (is.eof())
|
|
||||||
break;
|
|
||||||
std::getline(is, zm.other, '\"');
|
|
||||||
read_field_delim();
|
read_field_delim();
|
||||||
|
|
||||||
is.read(&ch, 1);
|
sis.read(&ch, 1);
|
||||||
std::getline(is, zm.territory, '\"');
|
std::getline(sis, zm.territory, '\"');
|
||||||
read_field_delim();
|
read_field_delim();
|
||||||
|
|
||||||
is.read(&ch, 1);
|
sis.read(&ch, 1);
|
||||||
std::getline(is, zm.type, '\"');
|
std::getline(sis, zm.type, '\"');
|
||||||
|
|
||||||
is.read(&ch, 1);
|
|
||||||
if (is.gcount() != 1 || ch != '\n')
|
|
||||||
error("record delimiter LF expected");
|
|
||||||
|
|
||||||
if (is.fail() || is.eof())
|
|
||||||
error("unexpected end of file, file read error or formatting error.");
|
|
||||||
|
|
||||||
|
sis.read(&ch, 1);
|
||||||
|
if (!sis.eof()) // Excess characters? We should have processed all in the line buffer.
|
||||||
|
error("Formatting error.");
|
||||||
++line;
|
++line;
|
||||||
mappings.push_back(std::move(zm));
|
mappings.push_back(std::move(zm));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user