classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] TimeZone/VMTimeZone split


From: Mark Wielaard
Subject: [cp-patches] TimeZone/VMTimeZone split
Date: Sun, 29 Aug 2004 19:28:34 +0200

Hi,

This splits java.util.TimeZone into a platform independent and a
platform dependent VMTimeZone class. It also incorparates the native
code from libgcj (translated to JNI from CNI).

The only (big) flaw is that it uses malloc() at this time (where libgcj
uses _Jv_Malloc of course). We should factor that out somehow in the
future. It is a little nicer then the libgcj version in that it gets rid
of the printf() call which some embedded devices like to ommit whenever
possible.

Since the flawed, non-working target native misc macro isn't used now
anymore (and I didn't see any versions of the macro for any non-posix
platform anyway) I removed it. I have not come up yet with a way to
integrate it into the target native layer for the moment. I would like
to do that in a way so that libgcj can really share most of our native
C/JNI code where possible (and still let them use CNI where possible).

If nobody comes up with a much better approach I would like to check
this version in now and make it "perfect" later when merging with libgcj
again. It is already pretty big and much better then the (non-working)
code we have now.

2004-08-28  Mark Wielaard  <address@hidden>

        * configure.ac: Check for sys/time.h, localtime_r, tm_gmtoff in
        struct tm and for for global timezone variable.
        * include/Makefile.am: Generate include/java_util_VMTimeZone.h.
        * include/java_util_TimeZone.h: Removed.
        * include/java_util_VMTimeZone.h: Added.
        * java/util/TimeZone.java (defaultZone): Use VMTimeZone.
        (getDefaultTimeZone): Make package private. Check that GMToffset
        contains at least one digit.
        (getDefaultTimeZoneId, readTimeZoneFile, readtzFile): (Re)Moved to
        VMTimeZone.
        * vm/reference/java/util/VMTimeZone.java: New file with above methods.
        * native/jni/java-util/Makefile.am: Compile new java_util_VMTimeZone.c.
        * native/jni/java-util/java_util_TimeZone.c: Removed.
        * native/jni/java-util/java_util_VMTimeZone.c: New file.
        * native/target/generic/target_generic_misc.h
        (TARGET_NATIVE_MISC_GET_TIMEZONE_STRING): Removed unused macro.
        * NEWS: Mention TimeZone/VMTimeZone split.

Comments?

Cheers,

Mark
Index: NEWS
===================================================================
RCS file: /cvsroot/classpath/classpath/NEWS,v
retrieving revision 1.49
diff -u -r1.49 NEWS
--- NEWS        28 Aug 2004 19:37:39 -0000      1.49
+++ NEWS        29 Aug 2004 17:26:32 -0000
@@ -20,6 +20,9 @@
   a reference implementation that most VMs can use.
 * java.lang.VMSystem has a new getenv(String) method and a reference C/JNI
   implementation that should work on most Posix like systems.
+* java.util.TimeZone has been split into a platform independent class and
+  a platform dependent class VMTimeZone.  GNU Classpath comes with a generic
+  way to get at the default time zone for Posix/GNU-like platforms.
 
 New in release 0.10 (Jul 9, 2004)
 
Index: configure.ac
===================================================================
RCS file: /cvsroot/classpath/classpath/configure.ac,v
retrieving revision 1.46
diff -u -r1.46 configure.ac
--- configure.ac        29 Aug 2004 16:32:13 -0000      1.46
+++ configure.ac        29 Aug 2004 17:26:32 -0000
@@ -124,6 +124,7 @@
   dnl BSD_COMP is defined; just including sys/filio.h is simpler.
   AC_CHECK_HEADERS(unistd.h sys/types.h sys/config.h sys/ioctl.h asm/ioctls.h)
   AC_CHECK_HEADERS(inttypes.h stdint.h utime.h sys/utime.h sys/filio.h)
+  AC_CHECK_HEADERS(sys/time.h)
 
   AC_EGREP_HEADER(uint32_t, stdint.h, AC_DEFINE(HAVE_INT32_DEFINED, 1, [Define 
to 1 if you have uint32_t]))
   AC_EGREP_HEADER(uint32_t, inttypes.h, AC_DEFINE(HAVE_INT32_DEFINED, 1, 
[Define to 1 if you have uint32_t]))
@@ -131,14 +132,37 @@
   AC_EGREP_HEADER(u_int32_t, sys/config.h, AC_DEFINE(HAVE_BSD_INT32_DEFINED, 
1, [Define to 1 if you have BSD u_int32_t]))
 
   AC_CHECK_FUNCS(ftruncate fsync select)
-  AC_CHECK_FUNCS(gethostname socket strerror fork pipe execve open close lseek 
\
-       fstat read write htonl memset htons connect getsockname sizeof 
getpeername \
-       bind listen accept recvfrom send sendto setsockopt getsockopt time 
mktime)
+  AC_CHECK_FUNCS(gethostname socket strerror fork pipe execve open close lseek)
+  AC_CHECK_FUNCS(fstat read write htonl memset htons connect getsockname)
+  AC_CHECK_FUNCS(sizeof getpeername bind listen accept recvfrom send sendto)
+  AC_CHECK_FUNCS(setsockopt getsockopt time mktime localtime_r)
 
   AC_HEADER_TIME
   AC_STRUCT_TM
   AC_STRUCT_TIMEZONE
 
+  AC_MSG_CHECKING([for tm_gmtoff in struct tm])
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]],[[struct tm tim; 
tim.tm_gmtoff = 0;]])],
+  [AC_DEFINE(STRUCT_TM_HAS_GMTOFF, 1, [Define if struct tm has tm_gmtoff 
field.])
+   AC_MSG_RESULT(yes)],
+  [AC_MSG_RESULT(no)
+   AC_MSG_CHECKING([for global timezone variable])
+   dnl FIXME: we don't want a link check here because that won't work
+   dnl when cross-compiling.  So instead we make an assumption that
+   dnl the header file will mention timezone if it exists.
+   dnl Don't find the win32 function timezone
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[void i(){long 
z2 = 2*timezone;}]])],
+     [AC_DEFINE(HAVE_TIMEZONE, 1, [Define if global 'timezone' exists.])
+      AC_MSG_RESULT(yes)],
+     [AC_MSG_RESULT(no)
+       AC_MSG_CHECKING([for global _timezone variable])
+       dnl FIXME: As above, don't want link check
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[long z2 = 
_timezone;]])],
+         [AC_DEFINE(HAVE_UNDERSCORE_TIMEZONE, 1,
+            [Define if your platform has the global _timezone variable.])
+          AC_MSG_RESULT(yes)],
+          [AC_MSG_RESULT(no)])])])
+
   AC_C_CONST
 
   dnl FIXME - does not allow cross compiling
Index: include/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/include/Makefile.am,v
retrieving revision 1.28
diff -u -r1.28 Makefile.am
--- include/Makefile.am 14 Aug 2004 17:19:50 -0000      1.28
+++ include/Makefile.am 29 Aug 2004 17:26:32 -0000
@@ -64,7 +64,7 @@
 $(top_srcdir)/include/java_nio_DirectByteBufferImpl.h \
 $(top_srcdir)/include/java_nio_MappedByteBufferImpl.h \
 $(top_srcdir)/include/java_nio_channels_Channels.h \
-$(top_srcdir)/include/java_util_TimeZone.h
+$(top_srcdir)/include/java_util_VMTimeZone.h
 
 if CREATE_JNI_HEADERS
 
@@ -188,7 +188,7 @@
        $(JAVAH) -o $@ java.nio.channels.Channels
 $(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h: 
$(top_srcdir)/gnu/java/nio/channels/FileChannelImpl.java
        $(JAVAH) -o $@ gnu.java.nio.channels.FileChannelImpl
-$(top_srcdir)/include/java_util_TimeZone.h: 
$(top_srcdir)/java/util/TimeZone.java
-       $(JAVAH) -o $@ java.util.TimeZone
+$(top_srcdir)/include/java_util_VMTimeZone.h: 
$(top_srcdir)/vm/reference/java/util/VMTimeZone.java
+       $(JAVAH) -o $@ java.util.VMTimeZone
 
 endif # CREATE_JNI_HEADERS
Index: include/java_util_TimeZone.h
===================================================================
RCS file: include/java_util_TimeZone.h
diff -N include/java_util_TimeZone.h
--- include/java_util_TimeZone.h        28 May 2004 17:27:57 -0000      1.3
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,19 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-
-#ifndef __java_util_TimeZone__
-#define __java_util_TimeZone__
-
-#include <jni.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-JNIEXPORT jstring JNICALL Java_java_util_TimeZone_getDefaultTimeZoneId (JNIEnv 
*env, jclass);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __java_util_TimeZone__ */
Index: include/java_util_VMTimeZone.h
===================================================================
RCS file: include/java_util_VMTimeZone.h
diff -N include/java_util_VMTimeZone.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ include/java_util_VMTimeZone.h      29 Aug 2004 17:26:32 -0000
@@ -0,0 +1,19 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+
+#ifndef __java_util_VMTimeZone__
+#define __java_util_VMTimeZone__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT jstring JNICALL Java_java_util_VMTimeZone_getSystemTimeZoneId 
(JNIEnv *env, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __java_util_VMTimeZone__ */
Index: java/util/TimeZone.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/util/TimeZone.java,v
retrieving revision 1.24
diff -u -r1.24 TimeZone.java
--- java/util/TimeZone.java     28 Aug 2004 19:39:30 -0000      1.24
+++ java/util/TimeZone.java     29 Aug 2004 17:26:33 -0000
@@ -38,9 +38,7 @@
 
 
 package java.util;
-import gnu.classpath.Configuration;
 
-import java.io.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.text.DateFormatSymbols;
@@ -90,14 +88,9 @@
   /**
    * Tries to get the default TimeZone for this system if not already
    * set.  It will call <code>getDefaultTimeZone(String)</code> with
-   * the result of
-   * <code>System.getProperty("user.timezone")</code>,
-   * <code>System.getenv("TZ")</code>,
-   * <code>readTimeZoneFile("/etc/timezone")</code>,
-   * <code>readtzFile("/etc/localtime")</code> and
-   * <code>getDefaultTimeZoneId()</code>
-   * till a supported TimeZone is found.
-   * If every method fails GMT is returned.
+   * the result of <code>System.getProperty("user.timezone")</code>.
+   * If that fails it calls <code>VMTimeZone.getDefaultTimeZoneId()</code>.
+   * If that also fails GMT is returned.
    */
   private static synchronized TimeZone defaultZone()
   {
@@ -109,11 +102,6 @@
            {
              public Object run()
              {
-               if (Configuration.INIT_LOAD_LIBRARY)
-                 {
-                   System.loadLibrary("javautil");
-                 }
-               
                TimeZone zone = null;
                
                // Prefer System property user.timezone.
@@ -121,37 +109,9 @@
                if (tzid != null && !tzid.equals(""))
                  zone = getDefaultTimeZone(tzid);
                
-               // See if TZ environment variable is set and accessible.
-               if (zone == null)
-                 {
-                   tzid = System.getenv("TZ");
-                   if (tzid != null && !tzid.equals(""))
-                     zone = getDefaultTimeZone(tzid);
-                 }
-               
-               // Try to parse /etc/timezone.
+               // Try platfom specific way.
                if (zone == null)
-                 {
-                   tzid = readTimeZoneFile("/etc/timezone");
-                   if (tzid != null && !tzid.equals(""))
-                     zone = getDefaultTimeZone(tzid);
-                 }
-               
-               // Try to parse /etc/localtime
-               if (zone == null)
-                 {
-                   tzid = readtzFile("/etc/localtime");
-                   if (tzid != null && !tzid.equals(""))
-                     zone = getDefaultTimeZone(tzid);
-                 }
-               
-               // Try some system specific way
-               if (zone == null)
-                 {
-                   tzid = getDefaultTimeZoneId();
-                   if (tzid != null && !tzid.equals(""))
-                     zone = getDefaultTimeZone(tzid);
-                 }
+                 zone = VMTimeZone.getDefaultTimeZoneId();
                
                // Fall back on GMT.
                if (zone == null)
@@ -843,238 +803,6 @@
   }
 
   /**
-   * This method returns a time zone id string which is in the form
-   * (standard zone name) or (standard zone name)(GMT offset) or
-   * (standard zone name)(GMT offset)(daylight time zone name).  The
-   * GMT offset can be in seconds, or where it is evenly divisible by
-   * 3600, then it can be in hours.  The offset must be the time to
-   * add to the local time to get GMT.  If a offset is given and the
-   * time zone observes daylight saving then the (daylight time zone
-   * name) must also be given (otherwise it is assumed the time zone
-   * does not observe any daylight savings).
-   * <p>
-   * The result of this method is given to getDefaultTimeZone(String)
-   * which tries to map the time zone id to a known TimeZone.  See
-   * that method on how the returned String is mapped to a real
-   * TimeZone object.
-   */
-  private static native String getDefaultTimeZoneId();
-
-  /**
-   * Tries to read the time zone name from a file. Only the first
-   * consecutive letters, digits, slashes, dashes and underscores are
-   * read from the file. If the file cannot be read or an IOException
-   * occurs null is returned.
-   * <p>
-   * The /etc/timezone file is not standard, but a lot of systems have
-   * it. If it exist the first line always contains a string
-   * describing the timezone of the host of domain. Some systems
-   * contain a /etc/TIMEZONE file which is used to set the TZ
-   * environment variable (which is checked before /etc/timezone is
-   * read).
-   */
-  private static String readTimeZoneFile(String file)
-  {
-    File f = new File(file);
-    if (!f.exists())
-      return null;
-
-    InputStreamReader isr = null;
-    try
-      {
-       FileInputStream fis = new FileInputStream(f);
-       BufferedInputStream bis = new BufferedInputStream(fis);
-       isr = new InputStreamReader(bis);
-       
-       StringBuffer sb = new StringBuffer();
-       int i = isr.read();
-       while (i != -1)
-         {
-           char c = (char) i;
-           if (Character.isLetter(c) || Character.isDigit(c)
-               || c == '/' || c == '-' || c == '_')
-             {
-               sb.append(c);
-               i = isr.read();
-             }
-           else
-             break;
-         }
-       return sb.toString();
-      }
-    catch (IOException ioe)
-      {
-       // Parse error, not a proper tzfile.
-       return null;
-      }
-    finally
-      {
-       try
-         {
-           if (isr != null)
-             isr.close();
-         }
-       catch (IOException ioe)
-         {
-           // Error while close, nothing we can do.
-         }
-      }
-  }
-
-  /**
-   * Tries to read a file as a "standard" tzfile and return a time
-   * zone id string as expected by <code>getDefaultTimeZone(String)</code>.
-   * If the file doesn't exist, an IOException occurs or it isn't a tzfile
-   * that can be parsed null is returned.
-   * <p>
-   * The tzfile structure (as also used by glibc) is described in the Olson
-   * tz database archive as can be found at
-   * <code>ftp://elsie.nci.nih.gov/pub/</code>.
-   * <p>
-   * At least the following platforms support the tzdata file format
-   * and /etc/localtime (GNU/Linux, Darwin, Solaris and FreeBSD at
-   * least). Some systems (like Darwin) don't start the file with the
-   * required magic bytes 'TZif', this implementation can handle
-   * that).
-   */
-  private static String readtzFile(String file)
-  {
-    File f = new File(file);
-    if (!f.exists())
-      return null;
-    
-    DataInputStream dis = null;
-    try
-      {
-        FileInputStream fis = new FileInputStream(f);
-        BufferedInputStream bis = new BufferedInputStream(fis);
-        dis = new DataInputStream(bis);
-       
-        // Make sure we are reading a tzfile.
-        byte[] tzif = new byte[4];
-        dis.readFully(tzif);
-        if (tzif[0] == 'T' && tzif[1] == 'Z'
-            && tzif[2] == 'i' && tzif[3] == 'f')
-         // Reserved bytes, ttisgmtcnt, ttisstdcnt and leapcnt
-         skipFully(dis, 16 + 3 * 4);
-       else
-         // Darwin has tzdata files that don't start with the TZif marker
-         skipFully(dis, 16 + 3 * 4 - 4);
-       
-       int timecnt = dis.readInt();
-       int typecnt = dis.readInt();
-       if (typecnt > 0)
-         {
-           int charcnt = dis.readInt();
-           // Transition times plus indexed transition times.
-           skipFully(dis, timecnt * (4 + 1));
-           
-           // Get last gmt_offset and dst/non-dst time zone names.
-           int abbrind = -1;
-           int dst_abbrind = -1;
-           int gmt_offset = 0;
-           while (typecnt-- > 0)
-             {
-               // gmtoff
-               int offset = dis.readInt();
-               int dst = dis.readByte();
-               if (dst == 0)
-                 {
-                   abbrind = dis.readByte();
-                   gmt_offset = offset;
-                 }
-               else
-                 dst_abbrind = dis.readByte();
-             }
-           
-           // gmt_offset is the offset you must add to UTC/GMT to
-           // get the local time, we need the offset to add to
-           // the local time to get UTC/GMT.
-           gmt_offset *= -1;
-           
-           // Turn into hours if possible.
-           if (gmt_offset % 3600 == 0)
-             gmt_offset /= 3600;
-           
-           if (abbrind >= 0)
-             {
-               byte[] names = new byte[charcnt];
-               dis.readFully(names);
-               int j = abbrind;
-               while (j < charcnt && names[j] != 0)
-                 j++;
-               
-               String zonename = new String(names, abbrind, j - abbrind,
-                                            "ASCII");
-               
-               String dst_zonename;
-               if (dst_abbrind >= 0)
-                 {
-                   j = dst_abbrind;
-                   while (j < charcnt && names[j] != 0)
-                     j++;
-                   dst_zonename = new String(names, dst_abbrind,
-                                             j - dst_abbrind, "ASCII");
-                 }
-               else
-                 dst_zonename = "";
-               
-               // Only use gmt offset when necessary.
-               // Also special case GMT+/- timezones.
-               String offset_string;
-               if ("".equals(dst_zonename)
-                   && (gmt_offset == 0
-                       || zonename.startsWith("GMT+")
-                       || zonename.startsWith("GMT-")))
-                 offset_string = "";
-               else
-                 offset_string = Integer.toString(gmt_offset);
-               
-               String id = zonename + offset_string + dst_zonename;
-               
-               return id;
-             }
-         }
-       
-       // Something didn't match while reading the file.
-       return null;
-      }
-    catch (IOException ioe)
-      {
-       // Parse error, not a proper tzfile.
-       return null;
-      }
-    finally
-      {
-       try
-         {
-           if (dis != null)
-             dis.close();
-         }
-       catch(IOException ioe)
-         {
-           // Error while close, nothing we can do.
-         }
-      }
-  }
-  
-  /**
-   * Skips the requested number of bytes in the given InputStream.
-   * Throws EOFException if not enough bytes could be skipped.
-   * Negative numbers of bytes to skip are ignored.
-   */
-  private static void skipFully(InputStream is, long l) throws IOException
-  {
-    while (l > 0)
-      {
-        long k = is.skip(l);
-        if (k <= 0)
-          throw new EOFException();
-        l -= k;
-      }
-  }
-  
-  /**
    * Maps a time zone name (with optional GMT offset and daylight time
    * zone name) to one of the known time zones.  This method called
    * with the result of <code>System.getProperty("user.timezone")</code>
@@ -1111,7 +839,7 @@
    * The standard time zone name for The Netherlands is "Europe/Amsterdam",
    * but can also be given as "CET-1CEST".
    */
-  private static TimeZone getDefaultTimeZone(String sysTimeZoneId)
+  static TimeZone getDefaultTimeZone(String sysTimeZoneId)
   {
     // First find start of GMT offset info and any Daylight zone name.
     int startGMToffset = 0;
@@ -1119,7 +847,11 @@
     for (int i = 0; i < sysTimeZoneIdLength && startGMToffset == 0; i++)
       {
        char c = sysTimeZoneId.charAt(i);
-       if (c == '+' || c == '-' || Character.isDigit(c))
+       if (Character.isDigit(c))
+         startGMToffset = i;
+       else if ((c == '+' || c == '-')
+                && i + 1 < sysTimeZoneIdLength
+                && Character.isDigit(sysTimeZoneId.charAt(i + 1)))
          startGMToffset = i;
       }
     
Index: native/jni/java-util/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/java-util/Makefile.am,v
retrieving revision 1.5
diff -u -r1.5 Makefile.am
--- native/jni/java-util/Makefile.am    21 May 2004 07:25:45 -0000      1.5
+++ native/jni/java-util/Makefile.am    29 Aug 2004 17:26:33 -0000
@@ -1,5 +1,5 @@
 pkglib_LTLIBRARIES = libjavautil.la
 
-libjavautil_la_SOURCES = java_util_TimeZone.c
+libjavautil_la_SOURCES = java_util_VMTimeZone.c
 
 libjavautil_la_LDFLAGS = @CLASSPATH_MODULE@
Index: native/jni/java-util/java_util_TimeZone.c
===================================================================
RCS file: native/jni/java-util/java_util_TimeZone.c
diff -N native/jni/java-util/java_util_TimeZone.c
--- native/jni/java-util/java_util_TimeZone.c   29 Mar 2004 07:07:39 -0000      
1.7
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,78 +0,0 @@
-/* TimeZone.c - Native methods for java.util.TimeZone
-   Copyright (C) 1999 Free Software Foundation, Inc.
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
- 
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING.  If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library.  Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module.  An independent module is a module which is not derived from
-or based on this library.  If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so.  If you do not wish to do so, delete this
-exception statement from your version. */
-
-/* do not move; needed here because of some macro definitions */
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <jni.h>
-
-#include "target_native.h"
-#include "target_native_misc.h"
-
-#include "java_util_TimeZone.h"
-
-/*
- * This method returns a time zone string that is used by the static
- * initializer in java.util.TimeZone to create the default timezone
- * instance.  This is a key into the timezone table used by
- * that class.
- *
- * Class:     java_util_TimeZone
- * Method:    getDefaultTimeZoneId
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_util_TimeZone_getDefaultTimeZoneId(JNIEnv *env, jclass clazz)
-{
-#ifdef HAVE_TZNAME
-  char    buffer[128];
-  int     result;
-  jstring retval;
-
-  TARGET_NATIVE_MISC_GET_TIMEZONE_STRING(buffer,sizeof(buffer),result);
-
-  retval = (*env)->NewStringUTF(env, buffer);
- 
-  return(retval);
-#else
-  return(0); /* added this statement (crashes without..:-) --Fridi. */
-#endif /* HAVE_TZNAME */
-}
-
Index: native/jni/java-util/java_util_VMTimeZone.c
===================================================================
RCS file: native/jni/java-util/java_util_VMTimeZone.c
diff -N native/jni/java-util/java_util_VMTimeZone.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ native/jni/java-util/java_util_VMTimeZone.c 29 Aug 2004 17:26:33 -0000
@@ -0,0 +1,220 @@
+/* VMTimeZone.c - Native method for java.util.VMTimeZone
+   Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include "config.h"
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <jni.h>
+
+#include "java_util_VMTimeZone.h"
+
+size_t jint_to_charbuf (char* bufend, jint num);
+
+/**
+ * This method returns a time zone id string which is in the form
+ * (standard zone name) or (standard zone name)(GMT offset) or
+ * (standard zone name)(GMT offset)(daylight time zone name).  The
+ * GMT offset can be in seconds, or where it is evenly divisible by
+ * 3600, then it can be in hours.  The offset must be the time to
+ * add to the local time to get GMT.  If a offset is given and the
+ * time zone observes daylight saving then the (daylight time zone
+ * name) must also be given (otherwise it is assumed the time zone
+ * does not observe any daylight savings).
+ * <p>
+ * The result of this method is given to getDefaultTimeZone(String)
+ * which tries to map the time zone id to a known TimeZone.  See
+ * that method on how the returned String is mapped to a real
+ * TimeZone object.
+ */
+JNIEXPORT jstring JNICALL
+Java_java_util_VMTimeZone_getSystemTimeZoneId(JNIEnv *env, jclass clazz)
+{
+  struct tm tim;
+#ifndef HAVE_LOCALTIME_R
+  struct tm *lt_tim;
+#endif
+#ifdef HAVE_TM_ZONE
+  int month;
+#endif
+  time_t current_time;
+  long tzoffset;
+  const char *tz1, *tz2;
+  char tzoff[11];
+  size_t tz1_len, tz2_len, tzoff_len;
+  char *tzid;
+  jstring retval;
+
+  time(&current_time);
+#ifdef HAVE_LOCALTIME_R
+  localtime_r(&current_time, &tim);
+#else
+  /* Fall back on non-thread safe localtime. */
+  lt_tim = localtime(&current_time);
+  memcpy(&tim, lt_tim, sizeof (struct tm));
+#endif
+  mktime(&tim);
+
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+  /* We will cycle through the months to make sure we hit dst. */
+  month = tim.tm_mon;
+  tz1 = tz2 = NULL;
+  while (tz1 == NULL || tz2 == NULL)
+    {
+      if (tim.tm_isdst > 0)
+        tz2 = tim.tm_zone;
+      else if (tz1 == NULL)
+        {
+          tz1 = tim.tm_zone;
+          month = tim.tm_mon;
+        }
+
+      if (tz1 == NULL || tz2 == NULL)
+        {
+          tim.tm_mon++;
+          tim.tm_mon %= 12;
+        }
+
+      if (tim.tm_mon == month && tz2 == NULL)
+        tz2 = "";
+      else
+        mktime(&tim);
+    }
+  /* We want to make sure the tm struct we use later on is not dst. */
+  tim.tm_mon = month;
+  mktime(&tim);
+#elif defined (HAVE_TZNAME)
+  /* If dst is never used, tzname[1] is the empty string. */
+  tzset();
+  tz1 = tzname[0];
+  tz2 = tzname[1];
+#else
+  /* Some targets have no concept of timezones. Assume GMT without dst. */
+  tz1 = "GMT";
+  tz2 = "";
+#endif
+
+#ifdef STRUCT_TM_HAS_GMTOFF
+  /* tm_gmtoff is the number of seconds that you must add to GMT to get
+     local time, we need the number of seconds to add to the local time
+     to get GMT. */
+  tzoffset = -1L * tim.tm_gmtoff;
+#elif HAVE_UNDERSCORE_TIMEZONE
+  tzoffset = _timezone;
+#elif HAVE_TIMEZONE
+  /* timezone is secs WEST of UTC. */
+  tzoffset = timezone; 
+#else
+  /* FIXME: there must be another global if neither tm_gmtoff nor timezone
+     is available, esp. if tzname is valid.
+     Richard Earnshaw <address@hidden> has suggested using difftime to
+     calculate between gmtime and localtime (and accounting for possible
+     daylight savings time) as an alternative. */
+  tzoffset = 0L;
+#endif
+
+  if ((tzoffset % 3600) == 0)
+    tzoffset = tzoffset / 3600;
+
+  tz1_len = strlen(tz1);
+  tz2_len = strlen(tz2);
+  tzoff_len = jint_to_charbuf (tzoff + 11, tzoffset);
+  tzid = (char*) malloc (tz1_len + tz2_len + tzoff_len + 1); /* FIXME alloc */
+  memcpy (tzid, tz1, tz1_len);
+  memcpy (tzid + tz1_len, tzoff + 11 - tzoff_len, tzoff_len);
+  memcpy (tzid + tz1_len + tzoff_len, tz2, tz2_len);
+  tzid[tz1_len + tzoff_len + tz2_len] = '\0';
+
+  retval = (*env)->NewStringUTF (env, tzid);
+  free (tzid);
+
+  return retval;
+}
+
+/* Put printed (decimal) representation of NUM in a buffer.
+   BUFEND marks the end of the buffer, which must be at least 11 chars long.
+   Returns the COUNT of chars written.  The result is in
+   (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive).
+
+   Note that libgcj has a slightly different version called _Jv_FormatInt
+   that works on jchar buffers.
+*/
+
+static size_t
+jint_to_charbuf (char* bufend, jint num)
+{
+  register char* ptr = bufend;
+  jboolean isNeg;
+  if (num < 0)
+    {
+      isNeg = JNI_TRUE;
+      num = -(num);
+      if (num < 0)
+        {
+          /* Must be MIN_VALUE, so handle this special case.
+            FIXME use 'unsigned jint' for num. */
+          *--ptr = '8';
+          num = 214748364;
+        }
+    }
+  else
+    isNeg = JNI_FALSE;
+
+    do
+      {
+        *--ptr = (char) ((int) '0' + (num % 10));
+        num /= 10;
+      }
+    while (num > 0);
+
+    if (isNeg)
+      *--ptr = '-';
+    return bufend - ptr;
+}
Index: native/target/generic/target_generic_misc.h
===================================================================
RCS file: 
/cvsroot/classpath/classpath/native/target/generic/target_generic_misc.h,v
retrieving revision 1.10
diff -u -r1.10 target_generic_misc.h
--- native/target/generic/target_generic_misc.h 9 Apr 2004 17:35:56 -0000       
1.10
+++ native/target/generic/target_generic_misc.h 29 Aug 2004 17:26:33 -0000
@@ -187,57 +187,6 @@
     } while (0)
 #endif
 
-/***********************************************************************\
-* Name       : TARGET_NATIVE_MISC_GET_TIMEZONE_STRING
-* Purpose    : get timezone string
-* Input      : string          - buffer for timezone string
-*              maxStringLength - max. string length
-* Output     : string - timezone string
-*              result - TARGET_NATIVE_OK or TARGET_NATIVE_ERROR
-* Return     : -
-* Side-effect: unknown
-* Notes      : set WITH_TIMEZONE_VARIABLE to timezone variable if not
-*              'timezone' (e. g. Cygwin)
-\***********************************************************************/
-
-#ifndef TARGET_NATIVE_MISC_GET_TIMEZONE_STRING
-  #if TIME_WITH_SYS_TIME
-     #include <sys/time.h>
-     #include <time.h>
-   #else
-     #if HAVE_SYS_TIME_H
-       #include <sys/time.h>
-     #else
-       #include <time.h>
-     #endif
-  #endif
-  #include <string.h>
-  #ifndef WITH_TIMEZONE_VARIABLE
-    #define WITH_TIMEZONE_VARIABLE timezone
-  #endif
-  #define 
TARGET_NATIVE_MISC_GET_TIMEZONE_STRING(string,maxStringLength,result) \
-    do { \
-      tzset(); \
-      \
-      if (strcmp(tzname[0],tzname[1])!=0) \
-      { \
-        
result=((strlen(tzname[0])+6)<=maxStringLength)?TARGET_NATIVE_OK:TARGET_NATIVE_ERROR;
 \
-        if (result==TARGET_NATIVE_OK) \
-        { \
-          
snprintf(string,maxStringLength,"%s%ld",tzname[0],((WITH_TIMEZONE_VARIABLE%3600)==0)?WITH_TIMEZONE_VARIABLE/3600:WITH_TIMEZONE_VARIABLE);
 \
-        } \
-      } \
-      else \
-      { \
-        
result=((strlen(tzname[0])+strlen(tzname[1])+6)<=maxStringLength)?TARGET_NATIVE_OK:TARGET_NATIVE_ERROR;
 \
-        if (result==TARGET_NATIVE_OK) \
-        { \
-          
snprintf(string,maxStringLength,"%s%ld%s",tzname[0],((WITH_TIMEZONE_VARIABLE%3600)==0)?WITH_TIMEZONE_VARIABLE/3600:WITH_TIMEZONE_VARIABLE,tzname[1]);
 \
-        } \
-      } \
-    } while (0)
-#endif
-
 /***************************** Functions *******************************/
 
 #ifdef __cplusplus
Index: vm/reference/java/util/VMTimeZone.java
===================================================================
RCS file: vm/reference/java/util/VMTimeZone.java
diff -N vm/reference/java/util/VMTimeZone.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ vm/reference/java/util/VMTimeZone.java      29 Aug 2004 17:26:33 -0000
@@ -0,0 +1,346 @@
+/* java.util.VMTimeZone
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.util;
+
+import gnu.classpath.Configuration;
+
+import java.io.*;
+
+/**
+ *
+ */
+final class VMTimeZone
+{
+  static
+  {
+    if (Configuration.INIT_LOAD_LIBRARY)
+      {
+       System.loadLibrary("javautil");
+      }
+  }
+               
+  /**
+   * This method returns a time zone id string which is in the form
+   * (standard zone name) or (standard zone name)(GMT offset) or
+   * (standard zone name)(GMT offset)(daylight time zone name).  The
+   * GMT offset can be in seconds, or where it is evenly divisible by
+   * 3600, then it can be in hours.  The offset must be the time to
+   * add to the local time to get GMT.  If a offset is given and the
+   * time zone observes daylight saving then the (daylight time zone
+   * name) must also be given (otherwise it is assumed the time zone
+   * does not observe any daylight savings).
+   * <p>
+   * The result of this method is given to the method
+   * TimeZone.getDefaultTimeZone(String) which tries to map the time
+   * zone id to a known TimeZone.  See that method on how the returned
+   * String is mapped to a real TimeZone object.
+   * <p>
+   * The reference implementation which is made for GNU/Posix like
+   * systems calls <code>System.getenv("TZ")</code>,
+   * <code>readTimeZoneFile("/etc/timezone")</code>,
+   * <code>readtzFile("/etc/localtime")</code> and finally
+   * <code>getSystemTimeZoneId()</code> till a supported TimeZone is
+   * found through <code>TimeZone.getDefaultTimeZone(String)</code>.
+   * If every method fails <code>null</code> is returned (which means
+   * the TimeZone code will fall back on GMT as default time zone).
+   * <p>
+   * Note that this method is called inside a
+   * <code>AccessController.doPrivileged()</code> block and runs with
+   * the priviliges of the java.util system classes.  It will only be
+   * called when the default time zone is not yet set, the system
+   * property user.timezone isn't set and it is requested for the
+   * first time.
+   */
+  static TimeZone getDefaultTimeZoneId()
+  {
+    TimeZone zone = null;
+
+    // See if TZ environment variable is set and accessible.
+    String tzid = System.getenv("TZ");
+    if (tzid != null && !tzid.equals(""))
+      zone = TimeZone.getDefaultTimeZone(tzid);
+
+    // Try to parse /etc/timezone.
+    if (zone == null)
+      {
+       tzid = readTimeZoneFile("/etc/timezone");
+       if (tzid != null && !tzid.equals(""))
+         zone = TimeZone.getDefaultTimeZone(tzid);
+      }
+    
+    // Try to parse /etc/localtime
+    if (zone == null)
+      {
+       tzid = readtzFile("/etc/localtime");
+       if (tzid != null && !tzid.equals(""))
+         zone = TimeZone.getDefaultTimeZone(tzid);
+      }
+
+    // Try some system specific way
+    if (zone == null)
+      {
+       tzid = getSystemTimeZoneId();
+       System.err.println("tzid: " + tzid);
+       if (tzid != null && !tzid.equals(""))
+         zone = TimeZone.getDefaultTimeZone(tzid);
+      }
+
+    return zone;
+  }
+
+  /**
+   * Tries to read the time zone name from a file. Only the first
+   * consecutive letters, digits, slashes, dashes and underscores are
+   * read from the file. If the file cannot be read or an IOException
+   * occurs null is returned.
+   * <p>
+   * The /etc/timezone file is not standard, but a lot of systems have
+   * it. If it exist the first line always contains a string
+   * describing the timezone of the host of domain. Some systems
+   * contain a /etc/TIMEZONE file which is used to set the TZ
+   * environment variable (which is checked before /etc/timezone is
+   * read).
+   */
+  private static String readTimeZoneFile(String file)
+  {
+    File f = new File(file);
+    if (!f.exists())
+      return null;
+
+    InputStreamReader isr = null;
+    try
+      {
+       FileInputStream fis = new FileInputStream(f);
+       BufferedInputStream bis = new BufferedInputStream(fis);
+       isr = new InputStreamReader(bis);
+       
+       StringBuffer sb = new StringBuffer();
+       int i = isr.read();
+       while (i != -1)
+         {
+           char c = (char) i;
+           if (Character.isLetter(c) || Character.isDigit(c)
+               || c == '/' || c == '-' || c == '_')
+             {
+               sb.append(c);
+               i = isr.read();
+             }
+           else
+             break;
+         }
+       return sb.toString();
+      }
+    catch (IOException ioe)
+      {
+       // Parse error, not a proper tzfile.
+       return null;
+      }
+    finally
+      {
+       try
+         {
+           if (isr != null)
+             isr.close();
+         }
+       catch (IOException ioe)
+         {
+           // Error while close, nothing we can do.
+         }
+      }
+  }
+
+  /**
+   * Tries to read a file as a "standard" tzfile and return a time
+   * zone id string as expected by <code>getDefaultTimeZone(String)</code>.
+   * If the file doesn't exist, an IOException occurs or it isn't a tzfile
+   * that can be parsed null is returned.
+   * <p>
+   * The tzfile structure (as also used by glibc) is described in the Olson
+   * tz database archive as can be found at
+   * <code>ftp://elsie.nci.nih.gov/pub/</code>.
+   * <p>
+   * At least the following platforms support the tzdata file format
+   * and /etc/localtime (GNU/Linux, Darwin, Solaris and FreeBSD at
+   * least). Some systems (like Darwin) don't start the file with the
+   * required magic bytes 'TZif', this implementation can handle
+   * that).
+   */
+  private static String readtzFile(String file)
+  {
+    File f = new File(file);
+    if (!f.exists())
+      return null;
+    
+    DataInputStream dis = null;
+    try
+      {
+        FileInputStream fis = new FileInputStream(f);
+        BufferedInputStream bis = new BufferedInputStream(fis);
+        dis = new DataInputStream(bis);
+       
+        // Make sure we are reading a tzfile.
+        byte[] tzif = new byte[4];
+        dis.readFully(tzif);
+        if (tzif[0] == 'T' && tzif[1] == 'Z'
+            && tzif[2] == 'i' && tzif[3] == 'f')
+         // Reserved bytes, ttisgmtcnt, ttisstdcnt and leapcnt
+         skipFully(dis, 16 + 3 * 4);
+       else
+         // Darwin has tzdata files that don't start with the TZif marker
+         skipFully(dis, 16 + 3 * 4 - 4);
+       
+       int timecnt = dis.readInt();
+       int typecnt = dis.readInt();
+       if (typecnt > 0)
+         {
+           int charcnt = dis.readInt();
+           // Transition times plus indexed transition times.
+           skipFully(dis, timecnt * (4 + 1));
+           
+           // Get last gmt_offset and dst/non-dst time zone names.
+           int abbrind = -1;
+           int dst_abbrind = -1;
+           int gmt_offset = 0;
+           while (typecnt-- > 0)
+             {
+               // gmtoff
+               int offset = dis.readInt();
+               int dst = dis.readByte();
+               if (dst == 0)
+                 {
+                   abbrind = dis.readByte();
+                   gmt_offset = offset;
+                 }
+               else
+                 dst_abbrind = dis.readByte();
+             }
+           
+           // gmt_offset is the offset you must add to UTC/GMT to
+           // get the local time, we need the offset to add to
+           // the local time to get UTC/GMT.
+           gmt_offset *= -1;
+           
+           // Turn into hours if possible.
+           if (gmt_offset % 3600 == 0)
+             gmt_offset /= 3600;
+           
+           if (abbrind >= 0)
+             {
+               byte[] names = new byte[charcnt];
+               dis.readFully(names);
+               int j = abbrind;
+               while (j < charcnt && names[j] != 0)
+                 j++;
+               
+               String zonename = new String(names, abbrind, j - abbrind,
+                                            "ASCII");
+               
+               String dst_zonename;
+               if (dst_abbrind >= 0)
+                 {
+                   j = dst_abbrind;
+                   while (j < charcnt && names[j] != 0)
+                     j++;
+                   dst_zonename = new String(names, dst_abbrind,
+                                             j - dst_abbrind, "ASCII");
+                 }
+               else
+                 dst_zonename = "";
+               
+               // Only use gmt offset when necessary.
+               // Also special case GMT+/- timezones.
+               String offset_string;
+               if ("".equals(dst_zonename)
+                   && (gmt_offset == 0
+                       || zonename.startsWith("GMT+")
+                       || zonename.startsWith("GMT-")))
+                 offset_string = "";
+               else
+                 offset_string = Integer.toString(gmt_offset);
+               
+               String id = zonename + offset_string + dst_zonename;
+               
+               return id;
+             }
+         }
+       
+       // Something didn't match while reading the file.
+       return null;
+      }
+    catch (IOException ioe)
+      {
+       // Parse error, not a proper tzfile.
+       return null;
+      }
+    finally
+      {
+       try
+         {
+           if (dis != null)
+             dis.close();
+         }
+       catch(IOException ioe)
+         {
+           // Error while close, nothing we can do.
+         }
+      }
+  }
+  
+  /**
+   * Skips the requested number of bytes in the given InputStream.
+   * Throws EOFException if not enough bytes could be skipped.
+   * Negative numbers of bytes to skip are ignored.
+   */
+  private static void skipFully(InputStream is, long l) throws IOException
+  {
+    while (l > 0)
+      {
+        long k = is.skip(l);
+        if (k <= 0)
+          throw new EOFException();
+        l -= k;
+      }
+  }
+
+  /**
+   * Tries to get the system time zone id through native code.
+   */
+  private static native String getSystemTimeZoneId();
+}

Attachment: signature.asc
Description: This is a digitally signed message part


reply via email to

[Prev in Thread] Current Thread [Next in Thread]