mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 07:56:17 +01:00
Win32 TimeZone Support: General refactoring
For code clarity and to pass tests
This commit is contained in:
parent
1ef6933cbe
commit
d12bb7ef72
628
glib/gtimezone.c
628
glib/gtimezone.c
@ -151,6 +151,12 @@ typedef struct
|
||||
gboolean isgmt;
|
||||
} TimeZoneDate;
|
||||
|
||||
/* POSIX Timezone abbreviations are typically 3 or 4 characters, but
|
||||
Microsoft uses 32-character names. We'll use one larger to ensure
|
||||
we have room for the terminating \0.
|
||||
*/
|
||||
#define NAME_SIZE 33
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint start_year;
|
||||
@ -158,8 +164,8 @@ typedef struct
|
||||
gint32 dlt_offset;
|
||||
TimeZoneDate dlt_start;
|
||||
TimeZoneDate dlt_end;
|
||||
const gchar *std_name;
|
||||
const gchar *dlt_name;
|
||||
gchar std_name[NAME_SIZE];
|
||||
gchar dlt_name[NAME_SIZE];
|
||||
} TimeZoneRule;
|
||||
|
||||
|
||||
@ -213,7 +219,8 @@ again:
|
||||
G_UNLOCK(time_zones);
|
||||
}
|
||||
|
||||
g_array_free (tz->t_info, TRUE);
|
||||
if (tz->t_info != NULL)
|
||||
g_array_free (tz->t_info, TRUE);
|
||||
if (tz->transitions != NULL)
|
||||
g_array_free (tz->transitions, TRUE);
|
||||
g_free (tz->name);
|
||||
@ -495,129 +502,141 @@ init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo)
|
||||
|
||||
#elif defined (G_OS_WIN32)
|
||||
|
||||
static void
|
||||
copy_windows_systemtime (SYSTEMTIME *s_time, TimeZoneDate *tzdate)
|
||||
{
|
||||
tzdate->sec = s_time->wSecond;
|
||||
tzdate->min = s_time->wMinute;
|
||||
tzdate->hour = s_time->wHour;
|
||||
tzdate->mon = s_time->wMonth;
|
||||
tzdate->year = s_time->wYear;
|
||||
tzdate->wday = s_time->wDayOfWeek ? s_time->wDayOfWeek : 7;
|
||||
|
||||
if (s_time->wYear)
|
||||
{
|
||||
tzdate->mday = s_time->wDay;
|
||||
tzdate->wday = 0;
|
||||
}
|
||||
else
|
||||
tzdate->week = s_time->wDay;
|
||||
}
|
||||
|
||||
/* UTC = local time + bias while local time = UTC + offset */
|
||||
static void
|
||||
rule_from_windows_time_zone_info (TimeZoneRule *rules,
|
||||
LONG Bias,
|
||||
LONG StandardBias,
|
||||
LONG DaylightBias,
|
||||
SYSTEMTIME StandardDate,
|
||||
SYSTEMTIME DaylightDate)
|
||||
rule_from_windows_time_zone_info (TimeZoneRule *rule,
|
||||
TIME_ZONE_INFORMATION *tzi)
|
||||
{
|
||||
/* Set offset */
|
||||
if (StandardDate.wMonth)
|
||||
if (tzi->StandardDate.wMonth)
|
||||
{
|
||||
rules->std_offset = -(Bias + StandardBias) * 60;
|
||||
rules->dlt_offset = -(Bias + DaylightBias) * 60;
|
||||
rule->std_offset = -(tzi->Bias + tzi->StandardBias) * 60;
|
||||
rule->dlt_offset = -(tzi->Bias + tzi->DaylightBias) * 60;
|
||||
copy_windows_systemtime (&(tzi->DaylightDate), &(rule->dlt_start));
|
||||
|
||||
rules->dlt_start.sec = DaylightDate.wSecond;
|
||||
rules->dlt_start.min = DaylightDate.wMinute;
|
||||
rules->dlt_start.hour = DaylightDate.wHour;
|
||||
rules->dlt_start.mon = DaylightDate.wMonth;
|
||||
rules->dlt_start.year = DaylightDate.wYear;
|
||||
rules->dlt_start.wday = DaylightDate.wDayOfWeek? DaylightDate.wDayOfWeek : 7;
|
||||
rule->dlt_start.isstd = FALSE;
|
||||
rule->dlt_start.isgmt = FALSE;
|
||||
copy_windows_systemtime (&(tzi->StandardDate), &(rule->dlt_end));
|
||||
|
||||
if (DaylightDate.wYear)
|
||||
{
|
||||
rules->dlt_start.mday = DaylightDate.wDay;
|
||||
rules->dlt_start.wday = 0;
|
||||
}
|
||||
else
|
||||
rules->dlt_start.week = DaylightDate.wDay;
|
||||
|
||||
rules->dlt_start.isstd = FALSE;
|
||||
rules->dlt_start.isgmt = FALSE;
|
||||
|
||||
rules->dlt_end.sec = StandardDate.wSecond;
|
||||
rules->dlt_end.min = StandardDate.wMinute;
|
||||
rules->dlt_end.hour = StandardDate.wHour;
|
||||
rules->dlt_end.mday = StandardDate.wDay;
|
||||
rules->dlt_end.mon = StandardDate.wMonth;
|
||||
rules->dlt_end.year = StandardDate.wYear;
|
||||
rules->dlt_end.wday = StandardDate.wDayOfWeek? StandardDate.wDayOfWeek : 7;
|
||||
|
||||
if (StandardDate.wYear)
|
||||
{
|
||||
rules->dlt_end.mday = StandardDate.wDay;
|
||||
rules->dlt_end.wday = 0;
|
||||
}
|
||||
else
|
||||
rules->dlt_end.week = StandardDate.wDay;
|
||||
|
||||
rules->dlt_end.isstd = FALSE;
|
||||
rules->dlt_end.isgmt = FALSE;
|
||||
rule->dlt_end.isstd = FALSE;
|
||||
rule->dlt_end.isgmt = FALSE;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
rules->std_offset = -Bias * 60;
|
||||
|
||||
rules->dlt_start.mon = 0;
|
||||
rule->std_offset = -tzi->Bias * 60;
|
||||
rule->dlt_start.mon = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rules_from_windows_time_zone (const gchar *identifier,
|
||||
TimeZoneRule **rules,
|
||||
gint *rules_num,
|
||||
gchar **std_name,
|
||||
gchar **dlt_name)
|
||||
static gchar*
|
||||
windows_default_tzname (void)
|
||||
{
|
||||
const gchar *subkey =
|
||||
"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation";
|
||||
HKEY key;
|
||||
gchar *key_name = NULL;
|
||||
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0,
|
||||
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = 0;
|
||||
if (RegQueryValueExA (key, "TimeZoneKeyName", NULL, NULL,
|
||||
NULL, &size) == ERROR_SUCCESS)
|
||||
{
|
||||
key_name = g_malloc ((gint)size);
|
||||
if (RegQueryValueExA (key, "TimeZoneKeyName", NULL, NULL,
|
||||
(LPBYTE)key_name, &size) != ERROR_SUCCESS)
|
||||
{
|
||||
g_free (key_name);
|
||||
key_name = NULL;
|
||||
}
|
||||
}
|
||||
RegCloseKey (key);
|
||||
}
|
||||
return key_name;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LONG Bias;
|
||||
LONG StandardBias;
|
||||
LONG DaylightBias;
|
||||
SYSTEMTIME StandardDate;
|
||||
SYSTEMTIME DaylightDate;
|
||||
} RegTZI;
|
||||
|
||||
static void
|
||||
system_time_copy (SYSTEMTIME *orig, SYSTEMTIME *target)
|
||||
{
|
||||
g_return_if_fail (orig != NULL);
|
||||
g_return_if_fail (target != NULL);
|
||||
|
||||
target->wYear = orig->wYear;
|
||||
target->wMonth = orig->wMonth;
|
||||
target->wDayOfWeek = orig->wDayOfWeek;
|
||||
target->wDay = orig->wDay;
|
||||
target->wHour = orig->wHour;
|
||||
target->wMinute = orig->wMinute;
|
||||
target->wSecond = orig->wSecond;
|
||||
target->wMilliseconds = orig->wMilliseconds;
|
||||
}
|
||||
|
||||
static void
|
||||
register_tzi_to_tzi (RegTZI *reg, TIME_ZONE_INFORMATION *tzi)
|
||||
{
|
||||
g_return_if_fail (reg != NULL);
|
||||
g_return_if_fail (tzi != NULL);
|
||||
tzi->Bias = reg->Bias;
|
||||
system_time_copy (&(reg->StandardDate), &(tzi->StandardDate));
|
||||
tzi->StandardBias = reg->StandardBias;
|
||||
system_time_copy (&(reg->DaylightDate), &(tzi->DaylightDate));
|
||||
tzi->DaylightBias = reg->DaylightBias;
|
||||
}
|
||||
|
||||
static gint
|
||||
rules_from_windows_time_zone (const gchar *identifier, TimeZoneRule **rules)
|
||||
{
|
||||
HKEY key;
|
||||
gchar *subkey, *subkey_dynamic;
|
||||
gchar *key_name;
|
||||
|
||||
/* REG_TZI_FORMAT */
|
||||
struct {
|
||||
LONG Bias;
|
||||
LONG StandardBias;
|
||||
LONG DaylightBias;
|
||||
SYSTEMTIME StandardDate;
|
||||
SYSTEMTIME DaylightDate;
|
||||
} tzi, tzi_prev;
|
||||
gchar *key_name = NULL;
|
||||
const gchar *reg_key =
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\";
|
||||
TIME_ZONE_INFORMATION tzi;
|
||||
DWORD size;
|
||||
gint rules_num = 0;
|
||||
RegTZI regtzi, regtzi_prev;
|
||||
|
||||
*rules = NULL;
|
||||
*rules_num = 0;
|
||||
*std_name = NULL;
|
||||
*dlt_name = NULL;
|
||||
|
||||
key_name = NULL;
|
||||
|
||||
if (!identifier)
|
||||
{
|
||||
subkey = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation";
|
||||
|
||||
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0,
|
||||
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
size = 0;
|
||||
if (RegQueryValueExA (key, "TimeZoneKeyName", NULL, NULL,
|
||||
NULL, &size) == ERROR_SUCCESS)
|
||||
{
|
||||
key_name = g_malloc (size);
|
||||
|
||||
if (RegQueryValueExA (key, "TimeZoneKeyName", NULL, NULL,
|
||||
(LPBYTE) key_name, &size) != ERROR_SUCCESS)
|
||||
{
|
||||
g_free (key_name);
|
||||
key_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey (key);
|
||||
}
|
||||
}
|
||||
key_name = windows_default_tzname ();
|
||||
else
|
||||
key_name = g_strdup (identifier);
|
||||
|
||||
if (!key_name)
|
||||
return FALSE;
|
||||
|
||||
subkey = g_strconcat ("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\",
|
||||
key_name,
|
||||
NULL);
|
||||
return 0;
|
||||
|
||||
subkey = g_strconcat (reg_key, key_name, NULL);
|
||||
subkey_dynamic = g_strconcat (subkey, "\\Dynamic DST", NULL);
|
||||
|
||||
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey_dynamic, 0,
|
||||
@ -637,16 +656,16 @@ rules_from_windows_time_zone (const gchar *identifier,
|
||||
(LPBYTE) &last, &size) != ERROR_SUCCESS)
|
||||
goto failed;
|
||||
|
||||
*rules_num = last - first + 2;
|
||||
*rules = g_new0 (TimeZoneRule, *rules_num);
|
||||
rules_num = last - first + 2;
|
||||
*rules = g_new0 (TimeZoneRule, rules_num);
|
||||
|
||||
for (year = first, i = 0; year <= last; year++)
|
||||
{
|
||||
s = g_strdup_printf ("%d", year);
|
||||
|
||||
size = sizeof tzi;
|
||||
size = sizeof regtzi;
|
||||
if (RegQueryValueExA (key, s, NULL, NULL,
|
||||
(LPBYTE) &tzi, &size) != ERROR_SUCCESS)
|
||||
(LPBYTE) ®tzi, &size) != ERROR_SUCCESS)
|
||||
{
|
||||
g_free (*rules);
|
||||
*rules = NULL;
|
||||
@ -655,19 +674,17 @@ rules_from_windows_time_zone (const gchar *identifier,
|
||||
|
||||
g_free (s);
|
||||
|
||||
if (year > first && memcmp (&tzi_prev, &tzi, sizeof tzi) == 0)
|
||||
if (year > first && memcmp (®tzi_prev, ®tzi, sizeof regtzi) == 0)
|
||||
continue;
|
||||
else
|
||||
memcpy (&tzi_prev, &tzi, sizeof tzi);
|
||||
|
||||
rule_from_windows_time_zone_info (&(*rules)[i], tzi.Bias,
|
||||
tzi.StandardBias, tzi.DaylightBias,
|
||||
tzi.StandardDate, tzi.DaylightDate);
|
||||
memcpy (®tzi_prev, ®tzi, sizeof regtzi);
|
||||
|
||||
register_tzi_to_tzi (®tzi, &tzi);
|
||||
rule_from_windows_time_zone_info (&(*rules)[i], &tzi);
|
||||
(*rules)[i++].start_year = year;
|
||||
}
|
||||
|
||||
*rules_num = i + 1;
|
||||
rules_num = i + 1;
|
||||
|
||||
failed:
|
||||
RegCloseKey (key);
|
||||
@ -675,16 +692,14 @@ failed:
|
||||
else if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0,
|
||||
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
size = sizeof tzi;
|
||||
size = sizeof regtzi;
|
||||
if (RegQueryValueExA (key, "TZI", NULL, NULL,
|
||||
(LPBYTE) &tzi, &size) == ERROR_SUCCESS)
|
||||
(LPBYTE) ®tzi, &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*rules_num = 2;
|
||||
rules_num = 2;
|
||||
*rules = g_new0 (TimeZoneRule, 2);
|
||||
|
||||
rule_from_windows_time_zone_info (&(*rules)[0], tzi.Bias,
|
||||
tzi.StandardBias, tzi.DaylightBias,
|
||||
tzi.StandardDate, tzi.DaylightDate);
|
||||
register_tzi_to_tzi (®tzi, &tzi);
|
||||
rule_from_windows_time_zone_info (&(*rules)[0], &tzi);
|
||||
}
|
||||
|
||||
RegCloseKey (key);
|
||||
@ -697,15 +712,15 @@ failed:
|
||||
if (*rules)
|
||||
{
|
||||
(*rules)[0].start_year = MIN_TZYEAR;
|
||||
if ((*rules)[*rules_num - 2].start_year < MAX_TZYEAR)
|
||||
(*rules)[*rules_num - 1].start_year = MAX_TZYEAR;
|
||||
if ((*rules)[rules_num - 2].start_year < MAX_TZYEAR)
|
||||
(*rules)[rules_num - 1].start_year = MAX_TZYEAR;
|
||||
else
|
||||
(*rules)[*rules_num - 1].start_year = (*rules)[*rules_num - 2].start_year + 1;
|
||||
(*rules)[rules_num - 1].start_year = (*rules)[rules_num - 2].start_year + 1;
|
||||
|
||||
return TRUE;
|
||||
return rules_num;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1101,199 +1116,183 @@ parse_tz_boundary (const gchar *identifier,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates an array of TimeZoneRule from a TZ environment variable
|
||||
* type of identifier. Should free rules, std_name and dlt_name
|
||||
* afterwards
|
||||
*/
|
||||
static gboolean
|
||||
rules_from_identifier (const gchar *identifier,
|
||||
TimeZoneRule **rules,
|
||||
gint *rules_num,
|
||||
gchar **std_name,
|
||||
gchar **dlt_name)
|
||||
static gint
|
||||
create_ruleset_from_rule (TimeZoneRule **rules, TimeZoneRule *rule)
|
||||
{
|
||||
const gchar *std_name_pos, *std_offset_pos;
|
||||
const gchar *dlt_name_pos, *dlt_offset_pos;
|
||||
|
||||
const gchar *start_date_pos, *end_date_pos;
|
||||
|
||||
const gchar *pos;
|
||||
gchar *buffer;
|
||||
gboolean ret;
|
||||
|
||||
gint32 std_offset, dlt_offset;
|
||||
TimeZoneDate dlt_start, dlt_end;
|
||||
|
||||
if (!identifier)
|
||||
return FALSE;
|
||||
|
||||
pos = identifier;
|
||||
|
||||
std_name_pos = pos;
|
||||
|
||||
/* Name is alpha */
|
||||
while ((*pos >= 'a' && 'z' >= *pos) || (*pos >= 'A' && 'Z' >= *pos))
|
||||
pos++;
|
||||
|
||||
/* Offset for standard required (format 1) */
|
||||
if (*pos == '\0')
|
||||
return FALSE;
|
||||
|
||||
/* Name should be three or more alphabetic characters */
|
||||
if (pos - identifier < 3)
|
||||
return FALSE;
|
||||
|
||||
std_offset_pos = pos;
|
||||
|
||||
/* Standard offset */
|
||||
while (*pos == '+' || *pos == '-' || *pos == ':' || (*pos >= '0' && '9' >= *pos))
|
||||
pos++;
|
||||
|
||||
buffer = g_strndup (std_offset_pos, pos - std_offset_pos);
|
||||
ret = parse_constant_offset (buffer, &std_offset);
|
||||
g_free (buffer);
|
||||
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
dlt_name_pos = pos;
|
||||
dlt_offset_pos = NULL;
|
||||
|
||||
/* Format 2 */
|
||||
if (*pos != '\0')
|
||||
{
|
||||
/* Name is alpha */
|
||||
while ((*pos >= 'a' && 'z' >= *pos) || (*pos >= 'A' && 'Z' >= *pos))
|
||||
pos++;
|
||||
|
||||
/* Name should be three or more alphabetic characters */
|
||||
if (pos - identifier < 3)
|
||||
return FALSE;
|
||||
|
||||
dlt_offset_pos = pos;
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
/* Start and end required (format 2) */
|
||||
if (*pos == '\0')
|
||||
return FALSE;
|
||||
#else
|
||||
if (*pos != '\0')
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Default offset is 1 hour less from standard offset */
|
||||
if (*pos++ == ',')
|
||||
dlt_offset = std_offset - 60 * 60;
|
||||
|
||||
else
|
||||
{
|
||||
/* Daylight offset */
|
||||
while (*pos == '+' || *pos == '-' || *pos == ':' || (*pos >= '0' && '9' >= *pos))
|
||||
pos++;
|
||||
|
||||
buffer = g_strndup (dlt_offset_pos, pos - dlt_offset_pos);
|
||||
ret = parse_constant_offset (buffer, &dlt_offset);
|
||||
g_free (buffer);
|
||||
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
/* Start and end required (format 2) */
|
||||
if (*pos++ != ',')
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Start date */
|
||||
start_date_pos = pos;
|
||||
|
||||
while (*pos != ',' && *pos != '\0')
|
||||
pos++;
|
||||
|
||||
/* End required (format 2) */
|
||||
if (*pos == '\0')
|
||||
return FALSE;
|
||||
|
||||
buffer = g_strndup (start_date_pos, pos++ - start_date_pos);
|
||||
ret = parse_tz_boundary (buffer, &dlt_start);
|
||||
g_free (buffer);
|
||||
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
/* End date */
|
||||
end_date_pos = pos;
|
||||
|
||||
while (*pos != '\0')
|
||||
pos++;
|
||||
|
||||
buffer = g_strndup (end_date_pos, pos - end_date_pos);
|
||||
ret = parse_tz_boundary (buffer, &dlt_end);
|
||||
g_free (buffer);
|
||||
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
*std_name = g_strndup (std_name_pos, std_offset_pos - std_name_pos);
|
||||
|
||||
if (dlt_name_pos != pos)
|
||||
*dlt_name = g_strndup (dlt_name_pos, dlt_offset_pos - dlt_name_pos);
|
||||
else
|
||||
{
|
||||
*dlt_name = NULL;
|
||||
dlt_start.mon = 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* If doesn't have offset for daylight then it is Windows format */
|
||||
if (dlt_offset_pos == pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Use US rules, Windows' default is Pacific Standard Time */
|
||||
dlt_offset = std_offset - 60 * 60;
|
||||
|
||||
if (rules_from_windows_time_zone ("Pacific Standard Time", rules, rules_num, NULL, NULL))
|
||||
{
|
||||
for (i = 0; i < *rules_num - 1; i++)
|
||||
{
|
||||
(*rules)[i].std_offset = -std_offset;
|
||||
(*rules)[i].dlt_offset = -dlt_offset;
|
||||
(*rules)[i].std_name = *std_name;
|
||||
(*rules)[i].dlt_name = *dlt_name;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
*rules_num = 2;
|
||||
*rules = g_new0 (TimeZoneRule, 2);
|
||||
|
||||
(*rules)[0].start_year = MIN_TZYEAR;
|
||||
(*rules)[1].start_year = MAX_TZYEAR;
|
||||
|
||||
(*rules)[0].std_offset = -std_offset;
|
||||
(*rules)[0].dlt_offset = -dlt_offset;
|
||||
(*rules)[0].dlt_start = dlt_start;
|
||||
(*rules)[0].dlt_end = dlt_end;
|
||||
(*rules)[0].std_name = *std_name;
|
||||
(*rules)[0].dlt_name = *dlt_name;
|
||||
(*rules)[0].std_offset = -rule->std_offset;
|
||||
(*rules)[0].dlt_offset = -rule->dlt_offset;
|
||||
(*rules)[0].dlt_start = rule->dlt_start;
|
||||
(*rules)[0].dlt_end = rule->dlt_end;
|
||||
strcpy (rule->std_name, (*rules)[0].std_name);
|
||||
strcpy (rule->dlt_name, (*rules)[0].dlt_name);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_offset (gchar **pos, gint32 *target)
|
||||
{
|
||||
gchar *buffer;
|
||||
gchar *target_pos = *pos;
|
||||
gboolean ret;
|
||||
|
||||
while (**pos == '+' || **pos == '-' || **pos == ':' ||
|
||||
(**pos >= '0' && '9' >= **pos))
|
||||
++(*pos);
|
||||
|
||||
buffer = g_strndup (target_pos, *pos - target_pos);
|
||||
ret = parse_constant_offset (buffer, target);
|
||||
g_free (buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_identifier_boundary (gchar **pos, TimeZoneDate *target)
|
||||
{
|
||||
gchar *buffer;
|
||||
gchar *target_pos = *pos;
|
||||
gboolean ret;
|
||||
|
||||
while (**pos != ',' && **pos != '\0')
|
||||
++(*pos);
|
||||
buffer = g_strndup (target_pos, *pos++ - target_pos);
|
||||
ret = parse_tz_boundary (buffer, target);
|
||||
g_free (buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static boolean
|
||||
set_tz_name (gchar **pos, gchar *buffer, guint size)
|
||||
{
|
||||
gchar *name_pos = *pos;
|
||||
guint len;
|
||||
|
||||
/* Name is ASCII alpha (Is this necessarily true?) */
|
||||
while (g_ascii_isalpha (**pos))
|
||||
++(*pos);
|
||||
|
||||
/* Offset for standard required (format 1) */
|
||||
if (**pos == '\0')
|
||||
return FALSE;
|
||||
|
||||
/* Name should be three or more alphabetic characters */
|
||||
if (*pos - name_pos < 3)
|
||||
return FALSE;
|
||||
|
||||
memset (buffer, 0, NAME_SIZE);
|
||||
/* name_pos isn't 0-terminated, so we have to limit the length expressly */
|
||||
len = *pos - name_pos > size - 1 ? size - 1 : *pos - name_pos;
|
||||
strncpy (buffer, name_pos, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_identifier_boundaries (gchar **pos, TimeZoneRule *tzr)
|
||||
{
|
||||
/* Default offset is 1 hour less from standard offset */
|
||||
if (*(*pos++) == ',')
|
||||
{
|
||||
tzr->dlt_offset = tzr->std_offset - 60 * 60;
|
||||
return TRUE;
|
||||
}
|
||||
/* Daylight offset */
|
||||
if (!parse_offset (pos, &(tzr->dlt_offset)))
|
||||
return FALSE;
|
||||
|
||||
/* Start and end required (format 2) */
|
||||
if (*(*pos++) != ',')
|
||||
return FALSE;
|
||||
|
||||
/* Start date */
|
||||
if (!parse_identifier_boundary (pos, &(tzr->dlt_start)) || **pos != ',')
|
||||
return FALSE;
|
||||
|
||||
/* End date */
|
||||
if (!parse_identifier_boundary (pos, &(tzr->dlt_end)))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates an array of TimeZoneRule from a TZ environment variable
|
||||
* type of identifier. Should free rules afterwards
|
||||
*/
|
||||
static gint
|
||||
rules_from_identifier (const gchar *identifier,
|
||||
TimeZoneRule **rules)
|
||||
{
|
||||
gchar *pos;
|
||||
TimeZoneRule tzr;
|
||||
|
||||
if (!identifier)
|
||||
return 0;
|
||||
|
||||
pos = (gchar*)identifier;
|
||||
memset (&tzr, 0, sizeof (tzr));
|
||||
/* Standard offset */
|
||||
if (!(set_tz_name (&pos, tzr.std_name, NAME_SIZE)) ||
|
||||
!parse_offset (&pos, &(tzr.std_offset)))
|
||||
return 0;
|
||||
|
||||
/* Format 2 */
|
||||
if (*pos != '\0')
|
||||
{
|
||||
if (!(set_tz_name (&pos, tzr.dlt_name, NAME_SIZE)))
|
||||
return 0;
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
/* Start and end required (format 2) */
|
||||
if (*pos == '\0')
|
||||
return 0;
|
||||
#else
|
||||
if (*pos != '\0')
|
||||
{
|
||||
#endif
|
||||
if (!parse_identifier_boundaries (&pos, &tzr))
|
||||
return 0;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* If doesn't have offset for daylight then it is Windows format */
|
||||
if (tzr.dlt_offset == 0)
|
||||
{
|
||||
int i;
|
||||
guint rules_num = 0;
|
||||
|
||||
/* Use US rules, Windows' default is Pacific Standard Time */
|
||||
tzr.dlt_offset = tzr.std_offset - 60 * 60;
|
||||
|
||||
if ((rules_num = rules_from_windows_time_zone ("Pacific Standard Time",
|
||||
rules)))
|
||||
{
|
||||
for (i = 0; i < rules_num - 1; i++)
|
||||
{
|
||||
(*rules)[i].std_offset = - tzr.std_offset;
|
||||
(*rules)[i].dlt_offset = - tzr.dlt_offset;
|
||||
strcpy ((*rules)[i].std_name, tzr.std_name);
|
||||
strcpy ((*rules)[i].dlt_name, tzr.dlt_name);
|
||||
}
|
||||
|
||||
return rules_num;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return create_ruleset_from_rule (rules, &tzr);
|
||||
}
|
||||
|
||||
/* Construction {{{1 */
|
||||
/**
|
||||
* g_time_zone_new:
|
||||
@ -1375,7 +1374,6 @@ g_time_zone_new (const gchar *identifier)
|
||||
GTimeZone *tz = NULL;
|
||||
TimeZoneRule *rules;
|
||||
gint rules_num;
|
||||
gchar *std_name, *dlt_name;
|
||||
|
||||
G_LOCK (time_zones);
|
||||
if (time_zones == NULL)
|
||||
@ -1399,14 +1397,10 @@ g_time_zone_new (const gchar *identifier)
|
||||
zone_for_constant_offset (tz, identifier);
|
||||
|
||||
if (tz->t_info == NULL &&
|
||||
rules_from_identifier (identifier,
|
||||
&rules, &rules_num,
|
||||
&std_name, &dlt_name))
|
||||
(rules_num = rules_from_identifier (identifier, &rules)))
|
||||
{
|
||||
init_zone_from_rules (tz, rules, rules_num);
|
||||
g_free (rules);
|
||||
g_free (std_name);
|
||||
g_free (dlt_name);
|
||||
}
|
||||
|
||||
if (tz->t_info == NULL)
|
||||
@ -1421,14 +1415,10 @@ g_time_zone_new (const gchar *identifier)
|
||||
g_bytes_unref (zoneinfo);
|
||||
}
|
||||
#elif defined (G_OS_WIN32)
|
||||
if (rules_from_windows_time_zone (identifier,
|
||||
&rules, &rules_num,
|
||||
&std_name, &dlt_name))
|
||||
if ((rules_num = rules_from_windows_time_zone (identifier, &rules)))
|
||||
{
|
||||
init_zone_from_rules (tz, rules, rules_num);
|
||||
g_free (rules);
|
||||
g_free (std_name);
|
||||
g_free (dlt_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1444,12 +1434,10 @@ g_time_zone_new (const gchar *identifier)
|
||||
{
|
||||
rules = g_new0 (TimeZoneRule, 2);
|
||||
|
||||
rule_from_windows_time_zone_info (&rules[0], tzi.Bias,
|
||||
tzi.StandardBias, tzi.DaylightBias,
|
||||
tzi.StandardDate, tzi.DaylightDate);
|
||||
rule_from_windows_time_zone_info (&rules[0], &tzi);
|
||||
|
||||
rules[0].std_name = NULL;
|
||||
rules[0].dlt_name = NULL;
|
||||
memset (rules[0].std_name, 0, NAME_SIZE);
|
||||
memset (rules[0].dlt_name, 0, NAME_SIZE);
|
||||
|
||||
rules[0].start_year = MIN_TZYEAR;
|
||||
rules[1].start_year = MAX_TZYEAR;
|
||||
|
Loading…
Reference in New Issue
Block a user