RE: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3) may not.
Benjamin Holzman [Wed, 19 Jul 2006 07:11:09 +0000 (03:11 -0400)]
From: "Benjamin Holzman" <bholzman@longitude.com>
Message-ID: <010801c6ab24$09b9ed30$ce0515ac@office.iseoptions.com>

p4raw-id: //depot/perl@29209

Configure
config_h.SH
reentr.h
t/op/time.t

index 1d428df..f0865f9 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -26,7 +26,7 @@
 
 # $Id: Head.U,v 3.0.1.9 1997/02/28 15:02:09 ram Exp $
 #
-# Generated on Mon Oct 23 17:35:45 CEST 2006 [metaconfig 3.0 PL70]
+# Generated on Mon Nov  6 10:30:43 CET 2006 [metaconfig 3.0 PL70]
 # (with additional metaconfig patches by perlbug@perl.org)
 
 cat >c1$$ <<EOF
@@ -549,6 +549,7 @@ d_ldbl_dig=''
 d_libm_lib_version=''
 d_link=''
 d_localtime_r=''
+d_localtime_r_needs_tzset=''
 localtime_r_proto=''
 d_locconv=''
 d_lockf=''
@@ -14514,6 +14515,59 @@ case "$d_localtime_r" in
        ;;
 esac
 
+: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*)
+       $cat >try.c <<EOCP
+/*  Does our libc's localtime_r call tzset ?
+ *  return 0 if so, 1 otherwise.
+ */
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+    time_t t = time(0L);
+    char w_tz[]="TZ" "=GMT+5",
+        e_tz[]="TZ" "=GMT-5",
+       *tz_e = (char*)malloc(16),
+       *tz_w = (char*)malloc(16);
+    struct tm tm_e, tm_w;
+    memset(&tm_e,'\0',sizeof(struct tm));
+    memset(&tm_w,'\0',sizeof(struct tm));
+    strcpy(tz_e,e_tz);
+    strcpy(tz_w,w_tz);
+
+    putenv(tz_e);
+    localtime_r(&t, &tm_e);
+
+    putenv(tz_w);
+    localtime_r(&t, &tm_w);
+
+    if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+       return 1;
+    return 0;
+}
+EOCP
+       set try
+       if eval $compile; then
+           if ./try; then
+               d_localtime_r_needs_tzset=undef;
+           else
+               d_localtime_r_needs_tzset=define;
+           fi;
+       else
+           d_localtime_r_needs_tzset=undef;
+       fi;
+     ;;
+  *)
+     d_localtime_r_needs_tzset=undef;
+     ;;
+esac
+$rm -f try try.* core
+
 : see if localeconv exists
 set localeconv d_locconv
 eval $inlibc
@@ -21505,6 +21559,7 @@ d_ldbl_dig='$d_ldbl_dig'
 d_libm_lib_version='$d_libm_lib_version'
 d_link='$d_link'
 d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
 d_locconv='$d_locconv'
 d_lockf='$d_lockf'
 d_longdbl='$d_longdbl'
index 7693c03..4812284 100644 (file)
@@ -2287,6 +2287,13 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
  *     This symbol, if defined, indicates that the localtime_r routine
  *     is available to localtime re-entrantly.
  */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif
+
 /* LOCALTIME_R_PROTO:
  *     This symbol encodes the prototype of localtime_r.
  *     It is zero if d_localtime_r is undef, and one of the
index e0273bd..ffa1090 100644 (file)
--- a/reentr.h
+++ b/reentr.h
@@ -1346,10 +1346,10 @@ typedef struct {
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef localtime
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) (L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
 #  endif /* if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1) */
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) (L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
 #  endif /* if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1) */
 #   endif /* HAS_LOCALTIME */
 #endif /* HAS_LOCALTIME_R */
index fc73a7b..2f01c7a 100755 (executable)
@@ -1,10 +1,10 @@
 #!./perl
 
 if ( $does_gmtime = gmtime(time) ) { 
-    print "1..7\n" 
+    print "1..8\n" 
 }
 else { 
-    print "1..4\n" 
+    print "1..5\n" 
 }
 
 
@@ -52,6 +52,13 @@ ok(localtime() =~ /^(Sun|Mon|Tue|Wed|Thu|Fri|Sat)[ ]
    'localtime(), scalar context'
   );
 
+# check that localtime respects changes to $ENV{TZ}
+$ENV{TZ} = "GMT-5";
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+$ENV{TZ} = "GMT+5";
+($sec,$min,$hour2,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+ok($hour != $hour2,                             'changes to $ENV{TZ} respected');
+
 exit 0 unless $does_gmtime;
 
 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($beg);