java_util_VMTimeZone.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* VMTimeZone.c - Native method for java.util.VMTimeZone
  2. Copyright (C) 1999, 2004 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. #include "config.h"
  32. #if TIME_WITH_SYS_TIME
  33. # include <sys/time.h>
  34. # include <time.h>
  35. #else
  36. # if HAVE_SYS_TIME_H
  37. # include <sys/time.h>
  38. # else
  39. # include <time.h>
  40. # endif
  41. #endif
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <stdlib.h>
  45. #include <jni.h>
  46. #include <jcl.h>
  47. #include "java_util_VMTimeZone.h"
  48. static size_t jint_to_charbuf (char *bufend, jint num);
  49. /**
  50. * This method returns a time zone id string which is in the form
  51. * (standard zone name) or (standard zone name)(GMT offset) or
  52. * (standard zone name)(GMT offset)(daylight time zone name). The
  53. * GMT offset can be in seconds, or where it is evenly divisible by
  54. * 3600, then it can be in hours. The offset must be the time to
  55. * add to the local time to get GMT. If a offset is given and the
  56. * time zone observes daylight saving then the (daylight time zone
  57. * name) must also be given (otherwise it is assumed the time zone
  58. * does not observe any daylight savings).
  59. * <p>
  60. * The result of this method is given to getDefaultTimeZone(String)
  61. * which tries to map the time zone id to a known TimeZone. See
  62. * that method on how the returned String is mapped to a real
  63. * TimeZone object.
  64. */
  65. JNIEXPORT jstring JNICALL
  66. Java_java_util_VMTimeZone_getSystemTimeZoneId (JNIEnv * env,
  67. jclass clazz
  68. __attribute__ ((__unused__)))
  69. {
  70. struct tm tim;
  71. #ifndef HAVE_LOCALTIME_R
  72. struct tm *lt_tim;
  73. #endif
  74. #ifdef HAVE_TM_ZONE
  75. int month;
  76. #endif
  77. time_t current_time;
  78. long tzoffset;
  79. const char *tz1, *tz2;
  80. char tzoff[11];
  81. size_t tz1_len, tz2_len, tzoff_len;
  82. char *tzid;
  83. jstring retval;
  84. time (&current_time);
  85. #ifdef HAVE_LOCALTIME_R
  86. localtime_r (&current_time, &tim);
  87. #else
  88. /* Fall back on non-thread safe localtime. */
  89. lt_tim = localtime (&current_time);
  90. memcpy (&tim, lt_tim, sizeof (struct tm));
  91. #endif
  92. mktime (&tim);
  93. #ifdef HAVE_STRUCT_TM_TM_ZONE
  94. /* We will cycle through the months to make sure we hit dst. */
  95. month = tim.tm_mon;
  96. tz1 = tz2 = NULL;
  97. while (tz1 == NULL || tz2 == NULL)
  98. {
  99. if (tim.tm_isdst > 0)
  100. tz2 = tim.tm_zone;
  101. else if (tz1 == NULL)
  102. {
  103. tz1 = tim.tm_zone;
  104. month = tim.tm_mon;
  105. }
  106. if (tz1 == NULL || tz2 == NULL)
  107. {
  108. tim.tm_mon++;
  109. tim.tm_mon %= 12;
  110. }
  111. if (tim.tm_mon == month && tz2 == NULL)
  112. tz2 = "";
  113. else
  114. mktime (&tim);
  115. }
  116. /* We want to make sure the tm struct we use later on is not dst. */
  117. tim.tm_mon = month;
  118. mktime (&tim);
  119. #elif defined (HAVE_TZNAME)
  120. /* If dst is never used, tzname[1] is the empty string. */
  121. tzset ();
  122. tz1 = tzname[0];
  123. tz2 = tzname[1];
  124. #else
  125. /* Some targets have no concept of timezones. Assume GMT without dst. */
  126. tz1 = "GMT";
  127. tz2 = "";
  128. #endif
  129. #ifdef STRUCT_TM_HAS_GMTOFF
  130. /* tm_gmtoff is the number of seconds that you must add to GMT to get
  131. local time, we need the number of seconds to add to the local time
  132. to get GMT. */
  133. tzoffset = -1L * tim.tm_gmtoff;
  134. #elif HAVE_UNDERSCORE_TIMEZONE
  135. /* On some systems _timezone is actually defined as time_t. */
  136. tzoffset = (long) _timezone;
  137. #elif HAVE_TIMEZONE
  138. /* timezone is secs WEST of UTC. */
  139. tzoffset = timezone;
  140. #else
  141. /* FIXME: there must be another global if neither tm_gmtoff nor timezone
  142. is available, esp. if tzname is valid.
  143. Richard Earnshaw <rearnsha@arm.com> has suggested using difftime to
  144. calculate between gmtime and localtime (and accounting for possible
  145. daylight savings time) as an alternative. */
  146. tzoffset = 0L;
  147. #endif
  148. if ((tzoffset % 3600) == 0)
  149. tzoffset = tzoffset / 3600;
  150. tz1_len = strlen (tz1);
  151. tz2_len = strlen (tz2);
  152. tzoff_len = jint_to_charbuf (tzoff + 11, tzoffset);
  153. tzid = (char *) malloc (tz1_len + tz2_len + tzoff_len + 1);
  154. if (tzid == NULL) {
  155. JCL_ThrowException (env, "java/lang/OutOfMemoryError",
  156. "malloc() failed");
  157. return 0;
  158. }
  159. memcpy (tzid, tz1, tz1_len);
  160. memcpy (tzid + tz1_len, tzoff + 11 - tzoff_len, tzoff_len);
  161. memcpy (tzid + tz1_len + tzoff_len, tz2, tz2_len);
  162. tzid[tz1_len + tzoff_len + tz2_len] = '\0';
  163. retval = (*env)->NewStringUTF (env, tzid);
  164. free (tzid);
  165. return retval;
  166. }
  167. /* Put printed (decimal) representation of NUM in a buffer.
  168. BUFEND marks the end of the buffer, which must be at least 11 chars long.
  169. Returns the COUNT of chars written. The result is in
  170. (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive).
  171. Note that libgcj has a slightly different version called _Jv_FormatInt
  172. that works on jchar buffers.
  173. */
  174. static size_t
  175. jint_to_charbuf (char *bufend, jint num)
  176. {
  177. register char *ptr = bufend;
  178. jboolean isNeg;
  179. if (num < 0)
  180. {
  181. isNeg = JNI_TRUE;
  182. num = -(num);
  183. if (num < 0)
  184. {
  185. /* Must be MIN_VALUE, so handle this special case.
  186. FIXME use 'unsigned jint' for num. */
  187. *--ptr = '8';
  188. num = 214748364;
  189. }
  190. }
  191. else
  192. isNeg = JNI_FALSE;
  193. do
  194. {
  195. *--ptr = (char) ((int) '0' + (num % 10));
  196. num /= 10;
  197. }
  198. while (num > 0);
  199. if (isNeg)
  200. *--ptr = '-';
  201. return bufend - ptr;
  202. }