reset timezone state when TZ env var changes

When the TZ env var is modified change fish's internal timezone state.

Fixes #3181.
This commit is contained in:
Kurtis Rader 2016-06-28 18:06:39 -07:00
parent 44cde9e0e9
commit dda890cf88
2 changed files with 58 additions and 0 deletions

View File

@ -13,6 +13,7 @@
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
@ -159,6 +160,24 @@ static mode_t get_umask() {
return res;
}
/// Check if the specified variable is a locale variable.
static bool var_is_timezone(const wcstring &key) { return key == L"TZ"; }
/// Properly sets all locale information.
static void handle_timezone(const wchar_t *env_var_name) {
debug(2, L"handle_timezone() called in response to '%ls' changing", env_var_name);
const env_var_t val = env_get_string(env_var_name, ENV_EXPORT);
const std::string &value = wcs2string(val);
const std::string &name = wcs2string(env_var_name);
debug(2, L"timezone var %s='%s'", name.c_str(), value.c_str());
if (val.empty()) {
unsetenv(name.c_str());
} else {
setenv(name.c_str(), value.c_str(), 1);
}
tzset();
}
/// Check if the specified variable is a locale variable.
static bool var_is_locale(const wcstring &key) {
for (size_t i = 0; locale_variable[i]; i++) {
@ -234,6 +253,8 @@ static void react_to_variable_change(const wcstring &key) {
handle_locale(key.c_str());
} else if (var_is_curses(key)) {
handle_curses(key.c_str());
} else if (var_is_timezone(key)) {
handle_timezone(key.c_str());
} else if (key == L"fish_term256" || key == L"fish_term24bit") {
update_fish_color_support();
reader_react_to_color_change();

View File

@ -3780,6 +3780,42 @@ static void test_string(void) {
}
}
/// Helper for test_timezone_env_vars().
long return_timezone_hour(time_t tstamp, const wchar_t *timezone) {
struct tm ltime;
char ltime_str[3];
char *str_ptr;
int n;
env_set(L"TZ", timezone, ENV_EXPORT);
localtime_r(&tstamp, &ltime);
n = strftime(ltime_str, 3, "%H", &ltime);
if (n != 2) {
err(L"strftime() returned %d, expected 2", n);
return 0;
}
return strtol(ltime_str, &str_ptr, 10);
}
/// Verify that setting special env vars have the expected effect on the current shell process.
static void test_timezone_env_vars(void) {
// Confirm changing the timezone affects fish's idea of the local time.
time_t tstamp = time(NULL);
long first_tstamp = return_timezone_hour(tstamp, L"UTC-1");
long second_tstamp = return_timezone_hour(tstamp, L"UTC-2");
long delta = second_tstamp - first_tstamp;
if (delta != 1 && delta != -23) {
err(L"expected a one hour timezone delta got %ld", delta);
}
}
/// Verify that setting special env vars have the expected effect on the current shell process.
static void test_env_vars(void) {
test_timezone_env_vars();
// TODO: Add tests for the locale and ncurses vars.
}
/// Main test.
int main(int argc, char **argv) {
// Look for the file tests/test.fish. We expect to run in a directory containing that file.
@ -3869,6 +3905,7 @@ int main(int argc, char **argv) {
if (should_test_function("history_races")) history_tests_t::test_history_races();
if (should_test_function("history_formats")) history_tests_t::test_history_formats();
if (should_test_function("string")) test_string();
if (should_test_function("env_vars")) test_env_vars();
// history_tests_t::test_history_speed();
say(L"Encountered %d errors in low-level tests", err_count);