summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--NEWS3
-rw-r--r--configure.ac37
-rw-r--r--include/Makefile.am6
-rw-r--r--include/java_util_TimeZone.h19
-rw-r--r--include/java_util_VMTimeZone.h19
-rw-r--r--java/util/TimeZone.java290
-rw-r--r--native/jni/java-util/Makefile.am2
-rw-r--r--native/jni/java-util/java_util_TimeZone.c78
-rw-r--r--native/jni/java-util/java_util_VMTimeZone.c220
-rw-r--r--native/target/generic/target_generic_misc.h51
-rw-r--r--vm/reference/java/util/VMTimeZone.java346
12 files changed, 654 insertions, 437 deletions
diff --git a/ChangeLog b/ChangeLog
index 4e0d5306d..c336f8fda 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2004-08-29 Mark Wielaard <mark@klomp.org>
+
+ * 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.
+
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/DefaultListSelectionModel.java
diff --git a/NEWS b/NEWS
index 44c21952a..ca4ca4799 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,9 @@ Runtime interface Changes:
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)
diff --git a/configure.ac b/configure.ac
index 0a5123bf9..a5125481f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -122,23 +122,48 @@ if test "x${COMPILE_JNI}" = xyes; then
dnl We check for sys/filio.h because Solaris 2.5 defines FIONREAD there.
dnl On that system, sys/ioctl.h will not include sys/filio.h unless
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([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]))
AC_EGREP_HEADER(u_int32_t, sys/types.h, AC_DEFINE(HAVE_BSD_INT32_DEFINED, 1, [Define to 1 if you have BSD u_int32_t]))
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([ftruncate fsync select])
+ AC_CHECK_FUNCS([gethostname socket strerror fork pipe execve open close])
+ AC_CHECK_FUNCS([lseek fstat read write htonl memset htons connect])
+ AC_CHECK_FUNCS([getsockname sizeof getpeername bind listen accept])
+ AC_CHECK_FUNCS([recvfrom send sendto setsockopt getsockopt time mktime])
+ AC_CHECK_FUNCS([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
diff --git a/include/Makefile.am b/include/Makefile.am
index 5a6b5a88d..942756ff2 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -64,7 +64,7 @@ $(top_srcdir)/include/java_net_NetworkInterface.h \
$(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 @@ $(top_srcdir)/include/java_nio_channels_Channels.h: $(top_srcdir)/java/nio/chann
$(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
diff --git a/include/java_util_TimeZone.h b/include/java_util_TimeZone.h
deleted file mode 100644
index 2854c6634..000000000
--- a/include/java_util_TimeZone.h
+++ /dev/null
@@ -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__ */
diff --git a/include/java_util_VMTimeZone.h b/include/java_util_VMTimeZone.h
new file mode 100644
index 000000000..8431e67b4
--- /dev/null
+++ b/include/java_util_VMTimeZone.h
@@ -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__ */
diff --git a/java/util/TimeZone.java b/java/util/TimeZone.java
index cc3c7a3d2..772f89305 100644
--- a/java/util/TimeZone.java
+++ b/java/util/TimeZone.java
@@ -38,9 +38,7 @@ exception statement from your version. */
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 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
/**
* 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 abstract class TimeZone implements java.io.Serializable, Cloneable
{
public Object run()
{
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("javautil");
- }
-
TimeZone zone = null;
// Prefer System property user.timezone.
@@ -121,37 +109,9 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
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 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
}
/**
- * 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 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
* 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 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
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;
}
diff --git a/native/jni/java-util/Makefile.am b/native/jni/java-util/Makefile.am
index f7497e6d5..7a06bb709 100644
--- a/native/jni/java-util/Makefile.am
+++ b/native/jni/java-util/Makefile.am
@@ -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@
diff --git a/native/jni/java-util/java_util_TimeZone.c b/native/jni/java-util/java_util_TimeZone.c
deleted file mode 100644
index 1c8cf5d2f..000000000
--- a/native/jni/java-util/java_util_TimeZone.c
+++ /dev/null
@@ -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 */
-}
-
diff --git a/native/jni/java-util/java_util_VMTimeZone.c b/native/jni/java-util/java_util_VMTimeZone.c
new file mode 100644
index 000000000..536f7bfef
--- /dev/null
+++ b/native/jni/java-util/java_util_VMTimeZone.c
@@ -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 <rearnsha@arm.com> 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;
+}
diff --git a/native/target/generic/target_generic_misc.h b/native/target/generic/target_generic_misc.h
index 19e3ab2d6..e3a4de6e5 100644
--- a/native/target/generic/target_generic_misc.h
+++ b/native/target/generic/target_generic_misc.h
@@ -187,57 +187,6 @@ Systems : all
} 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
diff --git a/vm/reference/java/util/VMTimeZone.java b/vm/reference/java/util/VMTimeZone.java
new file mode 100644
index 000000000..24e79f37e
--- /dev/null
+++ b/vm/reference/java/util/VMTimeZone.java
@@ -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();
+}