# HG changeset patch # User Richard Laager # Date 1141030154 0 # Node ID b04212d6b1150898656db89207d3e428ca2a20a0 # Parent 97545c71d20835d31aa6c3ff184f1d9343eaeac4 [gaim-migrate @ 15703] win32 TZ name to abbreviation conversion. This make the behavior consistent across platforms. committer: Tailor Script diff -r 97545c71d208 -r b04212d6b115 src/log.c --- a/src/log.c Mon Feb 27 08:35:13 2006 +0000 +++ b/src/log.c Mon Feb 27 08:49:14 2006 +0000 @@ -643,11 +643,7 @@ gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); tm = localtime(&log->time); -#ifdef _WIN32 - tz = ""; -#else tz = gaim_escape_filename(gaim_utf8_strftime("%Z", tm)); -#endif date = gaim_utf8_strftime("%Y-%m-%d.%H%M%S%z", tm); filename = g_strdup_printf("%s%s%s", date, tz, ext ? ext : ""); diff -r 97545c71d208 -r b04212d6b115 src/util.c --- a/src/util.c Mon Feb 27 08:35:13 2006 +0000 +++ b/src/util.c Mon Feb 27 08:49:14 2006 +0000 @@ -529,7 +529,10 @@ return buf; } - +#endif + +/* Windows doesn't HAVE_STRFTIME_Z_FORMAT, but this seems clearer. -- rlaager */ +#if !defined(HAVE_STRFTIME_Z_FORMAT) || defined(_WIN32) static size_t gaim_internal_strftime(char *s, size_t max, const char *format, const struct tm *tm) { const char *start; @@ -541,9 +544,10 @@ g_return_val_if_fail(format != NULL, 0); /* This is fairly efficient, and it only gets - * executed if the underlying system doesn't - * support the %z format string for strftime(), - * so I think it's good enough. -- rlaager */ + * executed on Windows or if the underlying + * system doesn't support the %z format string, + * for strftime() so I think it's good enough. + * -- rlaager */ for (c = start = format; *c ; c++) { if (*c != '%') @@ -551,6 +555,7 @@ c++; +#ifndef HAVE_STRFTIME_Z_FORMAT if (*c == 'z') { char *tmp = g_strdup_printf("%s%.*s%s", @@ -562,6 +567,20 @@ fmt = tmp; start = c + 1; } +#endif +#ifdef _WIN32 + if (*c == 'Z') + { + char *tmp = g_strdup_printf("%s%.*s%s", + fmt ? fmt : "", + c - start - 1, + start, + wgaim_get_timezone_abbreviation(tm)); + g_free(fmt); + fmt = tmp; + start = c + 1; + } +#endif } if (fmt != NULL) @@ -583,7 +602,7 @@ return strftime(s, max, format, tm); } -#else /* HAVE_STRFTIME_Z_FORMAT */ +#else /* HAVE_STRFTIME_Z_FORMAT && !_WIN32 */ #define gaim_internal_strftime strftime #endif diff -r 97545c71d208 -r b04212d6b115 src/util.h --- a/src/util.h Mon Feb 27 08:35:13 2006 +0000 +++ b/src/util.h Mon Feb 27 08:49:14 2006 +0000 @@ -223,6 +223,11 @@ * GMT. Required to emit RFC822-conformant dates * (using "%a, %d %b %Y %H:%M:%S %z"). (GNU)' * + * On Windows, this function also converts the results for %Z from a timezone + * name (as returned by the system strftime() %Z format string) to a timezone + * abbreviation (as is the case on Unix). As with %z, conversion specifiers + * should not be used. + * * @param format The format string, in UTF-8 * @param tm The time to format, or @c NULL to use the current local time * diff -r 97545c71d208 -r b04212d6b115 src/win32/libc_interface.c --- a/src/win32/libc_interface.c Mon Feb 27 08:35:13 2006 +0000 +++ b/src/win32/libc_interface.c Mon Feb 27 08:49:14 2006 +0000 @@ -1,9 +1,5 @@ /* * gaim - * - * File: libc_interface.c - * Date: October 14, 2002 - * Description: libc interface for Windows api * * Copyright (C) 2002-2003, Herman Bloggs * @@ -41,20 +37,9 @@ #define g_rename rename #define g_stat stat #endif -/* - * PROTOS - */ - -/* - * LOCALS - */ static char errbuf[1024]; -/* - * CODE - */ - /* helpers */ static int wgaim_is_socket( int fd ) { int optval; @@ -436,3 +421,520 @@ else return NULL; } + +/* + * Used by gaim_utf8_strftime() by way of gaim_internal_strftime() + * in src/util.c + * + * Code derived from PostgreSQL src/timezone/pgtz.c: + * http://developer.postgresql.org/cvsweb.cgi/pgsql/src/timezone/pgtz.c + */ + +/* +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ +static const struct +{ + const char *wstd; /* Windows name of standard timezone */ + const char *wdst; /* Windows name of daylight timezone */ + const char *ustd; /* Unix name of standard timezone */ + const char *udst; /* Unix name of daylight timezone */ +} win32_tzmap[] = +{ + /* + * This list was built from the contents of the registry at + * "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" + * on Windows XP Professional SP1 + */ + { + "Afghanistan Standard Time", "Afghanistan Daylight Time", + "AFT", "AFT" + }, + { + "Alaskan Standard Time", "Alaskan Daylight Time", + "AKST", "AKDT" + }, + { + "Arab Standard Time", "Arab Daylight Time", + "AST", "AST" + }, + { + "Arabian Standard Time", "Arabian Daylight Time", + "GST", "GST" + }, + { + "Arabic Standard Time", "Arabic Daylight Time", + "AST", "ADT" + }, + { + "Atlantic Standard Time", "Atlantic Daylight Time", + "AST", "ADT" + }, + { + "AUS Central Standard Time", "AUS Central Daylight Time", + "CST", "CST" + }, + { + "AUS Eastern Standard Time", "AUS Eastern Daylight Time", + "EST", "EST" + }, + { + "Azores Standard Time", "Azores Daylight Time", + "AZOT", "AZOST" + }, + { + "Canada Central Standard Time", "Canada Central Daylight Time", + "CST", "MDT" + }, + { + "Cape Verde Standard Time", "Cape Verde Daylight Time", + "CVT", "CVST" + }, + { + "Caucasus Standard Time", "Caucasus Daylight Time", + "AZT", "AZST" + }, + { + "Cen. Australia Standard Time", "Cen. Australia Daylight Time", + "CST", "CST" + }, + { + "Central America Standard Time", "Central America Daylight Time", + "CST", "CDT" + }, + { + "Central Asia Standard Time", "Central Asia Daylight Time", + "BDT", "BDT" + }, + { + "Central Europe Standard Time", "Central Europe Daylight Time", + "CET", "CEST" + }, + { + "Central European Standard Time", "Central European Daylight Time", + "CET", "CEST" + }, + { + "Central Pacific Standard Time", "Central Pacific Daylight Time", + "NCT", "NCST" + }, + { + "Central Standard Time", "Central Daylight Time", + "CST", "CDT" + }, + { + "China Standard Time", "China Daylight Time", + "HKT", "HKST" + }, + { + "Dateline Standard Time", "Dateline Daylight Time", + "GMT+12", "GMT+12" + }, + { + "E. Africa Standard Time", "E. Africa Daylight Time", + "EAT", "EAT" + }, + { + "E. Australia Standard Time", "E. Australia Daylight Time", + "EST", "EST" + }, + { + "E. Europe Standard Time", "E. Europe Daylight Time", + "EET", "EEST" + }, + { + "E. South America Standard Time", "E. South America Daylight Time", + "BRT", "BRST" + }, + { + "Eastern Standard Time", "Eastern Daylight Time", + "EST", "EDT" + }, + { + "Egypt Standard Time", "Egypt Daylight Time", + "EET", "EEST" + }, + { + "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", + "YEKT", "YEKST" + }, + { + "Fiji Standard Time", "Fiji Daylight Time", + "FJT", "FJST" + }, + { + "FLE Standard Time", "FLE Daylight Time", + "EET", "EEST" + }, + { + "GMT Standard Time", "GMT Daylight Time", + "GMT", "IST" + }, + { + "Greenland Standard Time", "Greenland Daylight Time", + "WGT", "WGST" + }, + { + "Greenwich Standard Time", "Greenwich Daylight Time", + "WET", "WEST" + }, + { + "GTB Standard Time", "GTB Daylight Time", + "EET", "EEST" + }, + { + "Hawaiian Standard Time", "Hawaiian Daylight Time", + "HST", "HPT" + }, + { + "India Standard Time", "India Daylight Time", + "IST", "IST" + }, + { + "Iran Standard Time", "Iran Daylight Time", + "IRST", "IRDT" + }, + { + "Jerusalem Standard Time", "Jerusalem Daylight Time", + "IST", "IDT" + }, + { + "Korea Standard Time", "Korea Daylight Time", + "KST", "KDT" + }, + { + "Mexico Standard Time", "Mexico Daylight Time", + "CST", "CDT" + }, + { + "Mexico Standard Time", "Mexico Daylight Time", + "BOT", "BOST" + }, + { + "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", + "GST", "GST" + }, + { + "Mountain Standard Time", "Mountain Daylight Time", + "MST", "MDT" + }, + { + "Myanmar Standard Time", "Myanmar Daylight Time", + "MMT", "MMT" + }, + { + "N. Central Asia Standard Time", "N. Central Asia Daylight Time", + "ALMT", "ALMST" + }, + { + "Nepal Standard Time", "Nepal Daylight Time", + "NPT", "NPT" + }, + { + "New Zealand Standard Time", "New Zealand Daylight Time", + "NZST", "NZDT" + }, + { + "Newfoundland Standard Time", "Newfoundland Daylight Time", + "NST", "NDT" + }, + { + "North Asia East Standard Time", "North Asia East Daylight Time", + "IRKT", "IRKST" + }, + { + "North Asia Standard Time", "North Asia Daylight Time", + "KRAT", "KRAST" + }, + { + "Pacific SA Standard Time", "Pacific SA Daylight Time", + "CLT", "CLST" + }, + { + "Pacific Standard Time", "Pacific Daylight Time", + "PST", "PDT" + }, + { + "Romance Standard Time", "Romance Daylight Time", + "CET", "CEST" + }, + { + "Russian Standard Time", "Russian Daylight Time", + "MSK", "MSD" + }, + { + "SA Eastern Standard Time", "SA Eastern Daylight Time", + "ART", "ARST" + }, + { + "SA Pacific Standard Time", "SA Pacific Daylight Time", + "COT", "COST" + }, + { + "SA Western Standard Time", "SA Western Daylight Time", + "VET", "VET" + }, + { + "Samoa Standard Time", "Samoa Daylight Time", + "SST", "NDT" + }, + { + "SE Asia Standard Time", "SE Asia Daylight Time", + "ICT", "ICT" + }, + { + "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", + "MYT", "MALST" + }, + { + "South Africa Standard Time", "South Africa Daylight Time", + "CAT", "CAT" + }, + { + "Sri Lanka Standard Time", "Sri Lanka Daylight Time", + "LKT", "IST" + }, + { + "Taipei Standard Time", "Taipei Daylight Time", + "CST", "CDT" + }, + { + "Tasmania Standard Time", "Tasmania Daylight Time", + "EST", "EST" + }, + { + "Tokyo Standard Time", "Tokyo Daylight Time", + "JST", "JDT" + }, + { + "Tonga Standard Time", "Tonga Daylight Time", + "TOT", "TOST" + }, + { + "US Eastern Standard Time", "US Eastern Daylight Time", + "EST", "EDT" + }, + { + "US Mountain Standard Time", "US Mountain Daylight Time", + "MST", "MDT" + }, + { + "Vladivostok Standard Time", "Vladivostok Daylight Time", + "VLAT", "VLAST" + }, + { + "W. Australia Standard Time", "W. Australia Daylight Time", + "WST", "WST" + }, + + /* Not mapped in PostgreSQL. + * + * I mapped this based on the following information... -- rlaager + * $ cd /usr/share/zoneinfo/Africa + * $ for i in * ; do echo `TZ=Africa/$i date +"%z %Z"` $i ; done | grep +0100 + * +0100 CET Algiers + * +0100 WAT Bangui + * +0100 WAT Brazzaville + * +0100 CET Ceuta + * +0100 WAT Douala + * +0100 WAT Kinshasa + * +0100 WAT Lagos + * +0100 WAT Libreville + * +0100 WAT Luanda + * +0100 WAT Malabo + * +0100 WAT Ndjamena + * +0100 WAT Niamey + * +0100 WAT Porto-Novo + * +0100 CET Tunis + **/ + { + "W. Central Africa Standard Time", "W. Central Africa Daylight Time", + "WAT", "WAT" + }, + + { + "W. Europe Standard Time", "W. Europe Daylight Time", + "CET", "CEST" + }, + { + "West Asia Standard Time", "West Asia Daylight Time", + "PKT", "PKST" + }, + { + "West Pacific Standard Time", "West Pacific Daylight Time", + "ChST", "ChST" + }, + { + "Yakutsk Standard Time", "Yakutsk Daylight Time", + "YAKT", "YAKST" + }, + { + NULL, NULL, + NULL, NULL + } +}; + +const char * +wgaim_get_timezone_abbreviation(const struct tm *tm) +{ + int i; + char tzname[128]; + char localtzname[256]; + HKEY rootKey; + int idx; + + if (!tm) + { + gaim_debug_warning("wgaim", "could not determine current date/time: localtime failed"); + return NULL; + } + + memset(tzname, 0, sizeof(tzname)); + strftime(tzname, sizeof(tzname) - 1, "%Z", tm); + + for (i = 0; win32_tzmap[i].wstd != NULL; i++) + { + if (strcmp(tzname, win32_tzmap[i].wstd) == 0) + { + gaim_debug_info("wgaim", "TZ \"%s\" matches Windows timezone \"%s\"", + win32_tzmap[i].ustd, tzname); + return win32_tzmap[i].ustd; + } + if (strcmp(tzname, win32_tzmap[i].wdst) == 0) + { + gaim_debug_info("wgaim", "TZ \"%s\" matches Windows timezone \"%s\"", + win32_tzmap[i].udst, tzname); + return win32_tzmap[i].udst; + } + } + + /* + * Localized Windows versions return localized names for the timezone. + * Scan the registry to find the English name, and then try matching + * against our table again. + */ + memset(localtzname, 0, sizeof(localtzname)); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", + 0, + KEY_READ, + &rootKey) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not open registry key to identify Windows timezone: %i", (int) GetLastError()); + return NULL; + } + + for (idx = 0;; idx++) + { + char keyname[256]; + char zonename[256]; + DWORD namesize; + FILETIME lastwrite; + HKEY key; + LONG r; + + memset(keyname, 0, sizeof(keyname)); + namesize = sizeof(keyname); + if ((r = RegEnumKeyEx(rootKey, + idx, + keyname, + &namesize, + NULL, + NULL, + NULL, + &lastwrite)) != ERROR_SUCCESS) + { + if (r == ERROR_NO_MORE_ITEMS) + break; + gaim_debug_warning("wgaim", "could not enumerate registry subkeys to identify Windows timezone: %i", (int) r); + break; + } + + if ((r = RegOpenKeyEx(rootKey, keyname, 0, KEY_READ, &key)) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not open registry subkey to identify Windows timezone: %i", (int) r); + break; + } + + memset(zonename, 0, sizeof(zonename)); + namesize = sizeof(zonename); + if ((r = RegQueryValueEx(key, "Std", NULL, NULL, zonename, &namesize)) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not query value for 'std' to identify Windows timezone: %i", (int) r); + RegCloseKey(key); + break; + } + if (strcmp(tzname, zonename) == 0) + { + /* Matched zone */ + strcpy(localtzname, keyname); + RegCloseKey(key); + break; + } + memset(zonename, 0, sizeof(zonename)); + namesize = sizeof(zonename); + if ((r = RegQueryValueEx(key, "Dlt", NULL, NULL, zonename, &namesize)) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not query value for 'dlt' to identify Windows timezone: %i", (int) r); + RegCloseKey(key); + break; + } + if (strcmp(tzname, zonename) == 0) + { + /* Matched DST zone */ + strcpy(localtzname, keyname); + RegCloseKey(key); + break; + } + + RegCloseKey(key); + } + + RegCloseKey(rootKey); + + if (localtzname[0]) + { + /* Found a localized name, so scan for that one too */ + for (i = 0; win32_tzmap[i].wstd != NULL; i++) + { + if (strcmp(localtzname, win32_tzmap[i].wstd) == 0) + { + gaim_debug_info("wgaim", "TZ \"%s\" matches localized Windows timezone \"%s\" (\"%s\")", + win32_tzmap[i].ustd, tzname, localtzname); + return win32_tzmap[i].ustd; + } + if (strcmp(localtzname, win32_tzmap[i].wdst) == 0) + { + gaim_debug_info("wgaim", "TZ \"%s\" matches localized Windows timezone \"%s\" (\"%s\")", + win32_tzmap[i].udst, tzname, localtzname); + return win32_tzmap[i].udst; + } + } + } + + gaim_debug_warning("wgaim", "could not find a match for Windows timezone \"%s\"", tzname); + return ""; +} diff -r 97545c71d208 -r b04212d6b115 src/win32/libc_interface.h --- a/src/win32/libc_interface.h Mon Feb 27 08:35:13 2006 +0000 +++ b/src/win32/libc_interface.h Mon Feb 27 08:49:14 2006 +0000 @@ -159,4 +159,7 @@ #define localtime_r( time, resultp ) \ wgaim_localtime_r( time, resultp ) +/* helper for gaim_utf8_strftime() by way of gaim_internal_strftime() in src/util.c */ +const char *wgaim_get_timezone_abbreviation(const struct tm *tm); + #endif /* _LIBC_INTERFACE_H_ */