From 7da0b018f2878484a68031800877f98872356594 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 19 Oct 2011 23:52:55 -0700 Subject: [PATCH] Time zone name fixes for non-ASCII locales (Bug#641, Bug#9794) * configure.in (AC_STRUCT_TM, AC_STRUCT_TIMEZONE, HAVE_TM_GMTOFF): Remove; no longer needed, now that we defer to strftime for time zone names. * src/editfns.c: Rewrite current-time-zone so that it invokes the equivalent of (format-time-string "%Z") to get the time zone name. This fixes a bug when the time zone name contains characters that need converting from the system time locale to Emacs internal format. This fixes a shortcoming that I introduced in my 1999-10-19 patch: that patch fixed format-time-string to do the conversion, but I forgot to fix current-time-zone. (format_time_string): New function, containing most of what Fformat_time_string used to contain. (Fformat_time_string): Rewrite in terms of format_time_string. This doesn't change this function's behavior. (current-time-zone): Rewrite to use format_time_string. This fixes the bug reported by Michael Schierl in . Jason Rumney's 2007-06-07 change worked around this bug, but didn't fix it. * src/systime.h (tzname, timezone): Remove no-longer-used declarations. --- ChangeLog | 7 ++++ configure.in | 6 ---- src/ChangeLog | 21 ++++++++++++ src/editfns.c | 91 ++++++++++++++++++++++----------------------------- src/systime.h | 11 ------- 5 files changed, 68 insertions(+), 68 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6147b1131f..9b9a7176b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-10-20 Paul Eggert + + Time zone name fixes for non-ASCII locales (Bug#641, Bug#9794) + * configure.in (AC_STRUCT_TM, AC_STRUCT_TIMEZONE, HAVE_TM_GMTOFF): + Remove; no longer needed, now that we defer to strftime for time + zone names. + 2011-10-18 Jan Djärv * configure.in (GLIB_REQUIRED, GTK_REQUIRED): Set to 2.10 (Bug#9786). diff --git a/configure.in b/configure.in index 4a5788600c..5b32e10853 100644 --- a/configure.in +++ b/configure.in @@ -1315,12 +1315,6 @@ AC_CHECK_HEADERS(net/if_dl.h, , , [AC_INCLUDES_DEFAULT AC_CHECK_FUNCS(getifaddrs freeifaddrs) dnl checks for structure members -AC_STRUCT_TM -AC_STRUCT_TIMEZONE -AC_CHECK_MEMBER(struct tm.tm_gmtoff, - [AC_DEFINE(HAVE_TM_GMTOFF, 1, - [Define to 1 if `tm_gmtoff' is member of `struct tm'.])],, - [#include ]) AC_CHECK_MEMBERS([struct ifreq.ifr_flags, struct ifreq.ifr_hwaddr, struct ifreq.ifr_netmask, struct ifreq.ifr_broadaddr, struct ifreq.ifr_addr, diff --git a/src/ChangeLog b/src/ChangeLog index c6a23a773d..36b205a120 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,24 @@ +2011-10-20 Paul Eggert + + Time zone name fixes for non-ASCII locales (Bug#641, Bug#9794) + * editfns.c: Rewrite current-time-zone so that it invokes + the equivalent of (format-time-string "%Z") to get the time zone name. + This fixes a bug when the time zone name contains characters that + need converting from the system time locale to Emacs internal format. + This fixes a shortcoming that I introduced in my 1999-10-19 patch: + that patch fixed format-time-string to do the conversion, but + I forgot to fix current-time-zone. + (format_time_string): New function, containing most of + what Fformat_time_string used to contain. + (Fformat_time_string): Rewrite in terms of format_time_string. + This doesn't change this function's behavior. + (current-time-zone): Rewrite to use format_time_string. + This fixes the bug reported by Michael Schierl in + . + Jason Rumney's 2007-06-07 change worked around this bug, but + didn't fix it. + * systime.h (tzname, timezone): Remove no-longer-used declarations. + 2011-10-19 Eli Zaretskii * xdisp.c (start_display): If the character at POS is displayed diff --git a/src/editfns.c b/src/editfns.c index 5f89391ce2..83cd4bd553 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -85,6 +85,8 @@ extern Lisp_Object w32_get_internal_run_time (void); #endif static void time_overflow (void) NO_RETURN; +static Lisp_Object format_time_string (char const *, ptrdiff_t, Lisp_Object, + int, time_t *, struct tm **); static int tm_diff (struct tm *, struct tm *); static void update_buffer_properties (EMACS_INT, EMACS_INT); @@ -1700,33 +1702,41 @@ For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z". usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */) (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object universal) { - time_t value; + time_t t; + struct tm *tm; + + CHECK_STRING (format_string); + format_string = code_convert_string_norecord (format_string, + Vlocale_coding_system, 1); + return format_time_string (SSDATA (format_string), SBYTES (format_string), + timeval, ! NILP (universal), &t, &tm); +} + +static Lisp_Object +format_time_string (char const *format, ptrdiff_t formatlen, + Lisp_Object timeval, int ut, time_t *tval, struct tm **tmp) +{ ptrdiff_t size; int usec; int ns; struct tm *tm; - int ut = ! NILP (universal); - - CHECK_STRING (format_string); - if (! (lisp_time_argument (timeval, &value, &usec) + if (! (lisp_time_argument (timeval, tval, &usec) && 0 <= usec && usec < 1000000)) error ("Invalid time specification"); ns = usec * 1000; - format_string = code_convert_string_norecord (format_string, - Vlocale_coding_system, 1); - /* This is probably enough. */ - size = SBYTES (format_string); + size = formatlen; if (size <= (STRING_BYTES_BOUND - 50) / 6) size = size * 6 + 50; BLOCK_INPUT; - tm = ut ? gmtime (&value) : localtime (&value); + tm = ut ? gmtime (tval) : localtime (tval); UNBLOCK_INPUT; if (! tm) time_overflow (); + *tmp = tm; synchronize_system_time_locale (); @@ -1737,9 +1747,7 @@ usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */) buf[0] = '\1'; BLOCK_INPUT; - result = emacs_nmemftime (buf, size, SSDATA (format_string), - SBYTES (format_string), - tm, ut, ns); + result = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); UNBLOCK_INPUT; if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0')) return code_convert_string_norecord (make_unibyte_string (buf, result), @@ -1747,9 +1755,7 @@ usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */) /* If buffer was too small, make it bigger and try again. */ BLOCK_INPUT; - result = emacs_nmemftime (NULL, (size_t) -1, - SSDATA (format_string), - SBYTES (format_string), + result = emacs_nmemftime (NULL, (size_t) -1, format, formatlen, tm, ut, ns); UNBLOCK_INPUT; if (STRING_BYTES_BOUND <= result) @@ -1994,51 +2000,34 @@ the data it can't find. */) { time_t value; struct tm *t; - struct tm gmt; - - if (!lisp_time_argument (specified_time, &value, NULL)) - t = NULL; - else - { - BLOCK_INPUT; - t = gmtime (&value); - if (t) - { - gmt = *t; - t = localtime (&value); - } - UNBLOCK_INPUT; - } + struct tm localtm; + struct tm *localt; + Lisp_Object zone_offset, zone_name; + + zone_offset = Qnil; + zone_name = format_time_string ("%Z", sizeof "%Z" - 1, specified_time, + 0, &value, &localt); + localtm = *localt; + BLOCK_INPUT; + t = gmtime (&value); + UNBLOCK_INPUT; if (t) { - int offset = tm_diff (t, &gmt); - char *s = 0; - char buf[sizeof "+00" + INT_STRLEN_BOUND (int)]; - -#ifdef HAVE_TM_ZONE - if (t->tm_zone) - s = (char *)t->tm_zone; -#else /* not HAVE_TM_ZONE */ -#ifdef HAVE_TZNAME - if (t->tm_isdst == 0 || t->tm_isdst == 1) - s = tzname[t->tm_isdst]; -#endif -#endif /* not HAVE_TM_ZONE */ - - if (!s) + int offset = tm_diff (&localtm, t); + zone_offset = make_number (offset); + if (SCHARS (zone_name) == 0) { /* No local time zone name is available; use "+-NNNN" instead. */ int m = offset / 60; int am = offset < 0 ? - m : m; + char buf[sizeof "+00" + INT_STRLEN_BOUND (int)]; sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60); - s = buf; + zone_name = build_string (buf); } - - return Fcons (make_number (offset), Fcons (build_string (s), Qnil)); } - else - return Fmake_list (make_number (2), Qnil); + + return list2 (zone_offset, zone_name); } /* This holds the value of `environ' produced by the previous diff --git a/src/systime.h b/src/systime.h index bed9ed4aa7..b90372dbe2 100644 --- a/src/systime.h +++ b/src/systime.h @@ -38,17 +38,6 @@ typedef unsigned long Time; # endif #endif -#ifdef HAVE_TZNAME -#ifndef tzname /* For SGI. */ -extern char *tzname[]; /* RS6000 and others want it this way. */ -#endif -#endif - -/* SVr4 doesn't actually declare this in its #include files. */ -#ifdef USG5_4 -extern time_t timezone; -#endif - /* On some configurations (hpux8.0, X11R4), sys/time.h and X11/Xos.h disagree about the name of the guard symbol. */ #ifdef HPUX -- 2.20.1