mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			504 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			504 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
| // natSystem.cc - Native code implementing System class.
 | ||
| 
 | ||
| /* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
 | ||
| 
 | ||
|    This file is part of libgcj.
 | ||
| 
 | ||
| This software is copyrighted work licensed under the terms of the
 | ||
| Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
 | ||
| details.  */
 | ||
| 
 | ||
| #include <config.h>
 | ||
| 
 | ||
| #include <stdio.h>
 | ||
| #include <string.h>
 | ||
| #include <stdlib.h>
 | ||
| 
 | ||
| #include "posix.h"
 | ||
| 
 | ||
| #ifdef HAVE_PWD_H
 | ||
| #include <pwd.h>
 | ||
| #endif
 | ||
| #include <errno.h>
 | ||
| 
 | ||
| #ifdef HAVE_UNAME
 | ||
| #include <sys/utsname.h>
 | ||
| #endif
 | ||
| 
 | ||
| #ifdef HAVE_LOCALE_H
 | ||
| #include <locale.h>
 | ||
| #endif
 | ||
| 
 | ||
| #ifdef HAVE_LANGINFO_H
 | ||
| #include <langinfo.h>
 | ||
| #endif
 | ||
| 
 | ||
| #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 <gcj/cni.h>
 | ||
| #include <jvm.h>
 | ||
| #include <java-props.h>
 | ||
| #include <java/lang/System.h>
 | ||
| #include <java/lang/Class.h>
 | ||
| #include <java/lang/ArrayStoreException.h>
 | ||
| #include <java/lang/ArrayIndexOutOfBoundsException.h>
 | ||
| #include <java/lang/NullPointerException.h>
 | ||
| #include <java/lang/StringBuffer.h>
 | ||
| #include <java/util/Properties.h>
 | ||
| #include <java/util/TimeZone.h>
 | ||
| #include <java/io/PrintStream.h>
 | ||
| #include <java/io/InputStream.h>
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| void
 | ||
| java::lang::System::setErr (java::io::PrintStream *newErr)
 | ||
| {
 | ||
|   checkSetIO ();
 | ||
|   // This violates `final' semantics.  Oh well.
 | ||
|   err = newErr;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| java::lang::System::setIn (java::io::InputStream *newIn)
 | ||
| {
 | ||
|   checkSetIO ();
 | ||
|   // This violates `final' semantics.  Oh well.
 | ||
|   in = newIn;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| java::lang::System::setOut (java::io::PrintStream *newOut)
 | ||
| {
 | ||
|   checkSetIO ();
 | ||
|   // This violates `final' semantics.  Oh well.
 | ||
|   out = newOut;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| java::lang::System::arraycopy (jobject src, jint src_offset,
 | ||
| 			       jobject dst, jint dst_offset,
 | ||
| 			       jint count)
 | ||
| {
 | ||
|   if (! src || ! dst)
 | ||
|     _Jv_Throw (new NullPointerException);
 | ||
| 
 | ||
|   jclass src_c = src->getClass();
 | ||
|   jclass dst_c = dst->getClass();
 | ||
|   jclass src_comp = src_c->getComponentType();
 | ||
|   jclass dst_comp = dst_c->getComponentType();
 | ||
| 
 | ||
|   if (! src_c->isArray() || ! dst_c->isArray()
 | ||
|       || src_comp->isPrimitive() != dst_comp->isPrimitive()
 | ||
|       || (src_comp->isPrimitive() && src_comp != dst_comp))
 | ||
|     _Jv_Throw (new ArrayStoreException);
 | ||
| 
 | ||
|   __JArray *src_a = (__JArray *) src;
 | ||
|   __JArray *dst_a = (__JArray *) dst;
 | ||
|   if (src_offset < 0 || dst_offset < 0 || count < 0
 | ||
|       || src_offset + count > src_a->length
 | ||
|       || dst_offset + count > dst_a->length)
 | ||
|     _Jv_Throw (new ArrayIndexOutOfBoundsException);
 | ||
| 
 | ||
|   // Do-nothing cases.
 | ||
|   if ((src == dst && src_offset == dst_offset)
 | ||
|       || ! count)
 | ||
|     return;
 | ||
| 
 | ||
|   // If both are primitive, we can optimize trivially.  If DST
 | ||
|   // components are always assignable from SRC components, then we
 | ||
|   // will never need to raise an error, and thus can do the
 | ||
|   // optimization.  If source and destinations are the same, then we
 | ||
|   // know that the assignability premise always holds.
 | ||
|   const bool prim = src_comp->isPrimitive();
 | ||
|   if (prim || dst_comp->isAssignableFrom(src_comp) || src == dst)
 | ||
|     {
 | ||
|       const size_t size = (prim ? src_comp->size()
 | ||
| 			   : sizeof elements((jobjectArray)src)[0]);
 | ||
| 
 | ||
|       char *src_elts = _Jv_GetArrayElementFromElementType (src, src_comp);
 | ||
|       src_elts += size * src_offset;
 | ||
| 
 | ||
|       char *dst_elts = _Jv_GetArrayElementFromElementType (dst, dst_comp);
 | ||
|       dst_elts += size * dst_offset;
 | ||
| 
 | ||
| #if HAVE_MEMMOVE
 | ||
|       // We don't bother trying memcpy.  It can't be worth the cost of
 | ||
|       // the check.
 | ||
|       // Don't cast to (void*), as memmove may expect (char*)
 | ||
|       memmove (dst_elts, src_elts, count * size);
 | ||
| #else
 | ||
|       bcopy (src_elts, dst_elts, count * size);
 | ||
| #endif
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       jobject *src_elts = elements ((jobjectArray) src_a) + src_offset;
 | ||
|       jobject *dst_elts = elements ((jobjectArray) dst_a) + dst_offset;
 | ||
| 
 | ||
|       for (int i = 0; i < count; ++i)
 | ||
| 	{
 | ||
| 	  if (*src_elts
 | ||
| 	      && ! dst_comp->isAssignableFrom((*src_elts)->getClass()))
 | ||
| 	    _Jv_Throw (new ArrayStoreException);
 | ||
| 	  *dst_elts++ = *src_elts++;
 | ||
| 	}
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| jlong
 | ||
| java::lang::System::currentTimeMillis (void)
 | ||
| {
 | ||
|   struct timeval tv;
 | ||
|   _Jv_gettimeofday (&tv);
 | ||
|   return (jlong) tv.tv_sec * 1000 + tv.tv_usec / 1000;
 | ||
| }
 | ||
| 
 | ||
| jint
 | ||
| java::lang::System::identityHashCode (jobject obj)
 | ||
| {
 | ||
|   return _Jv_HashCode (obj);
 | ||
| }
 | ||
| 
 | ||
| #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
 | ||
|     && defined (HAVE_NL_LANGINFO)
 | ||
| 
 | ||
| static char *
 | ||
| file_encoding ()
 | ||
| {
 | ||
|   setlocale (LC_CTYPE, "");
 | ||
|   char *e = nl_langinfo (CODESET);
 | ||
|   if (e == NULL || *e == '\0')
 | ||
|     e = "8859_1";
 | ||
|   return e;
 | ||
| }
 | ||
| 
 | ||
| #define DEFAULT_FILE_ENCODING file_encoding ()
 | ||
| 
 | ||
| #endif
 | ||
| 
 | ||
| #ifndef DEFAULT_FILE_ENCODING
 | ||
| #define DEFAULT_FILE_ENCODING "8859_1"
 | ||
| #endif
 | ||
| 
 | ||
| static char *default_file_encoding = DEFAULT_FILE_ENCODING;
 | ||
| 
 | ||
| #if HAVE_GETPWUID_R
 | ||
| /* Use overload resolution to find out the signature of getpwuid_r.  */
 | ||
| 
 | ||
|   /* This is Posix getpwuid_r.  */
 | ||
| template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
 | ||
| static inline int
 | ||
| getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
 | ||
| 				   T_buf *buf_r, T_len len_r,
 | ||
| 				   T_passwd **pwd_entry_ptr),
 | ||
| 		 uid_t user_id, struct passwd *pwd_r,
 | ||
| 		 char *buf_r, size_t len_r, struct passwd **pwd_entry)
 | ||
| {
 | ||
|   return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
 | ||
| }
 | ||
| 
 | ||
| /* This is used on HPUX 10.20 */
 | ||
| template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
 | ||
| static inline int
 | ||
| getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
 | ||
| 				   T_buf *buf_r, T_len len_r),
 | ||
| 		 uid_t user_id, struct passwd *pwd_r,
 | ||
| 		 char *buf_r, size_t len_r, struct passwd **pwd_entry)
 | ||
| {
 | ||
|   return getpwuid_r (user_id, pwd_r, buf_r, len_r);
 | ||
| }
 | ||
| 
 | ||
| /* This is used on IRIX 5.2.  */
 | ||
| template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
 | ||
| static inline int
 | ||
| getpwuid_adaptor(T_passwd * (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
 | ||
| 					  T_buf *buf_r, T_len len_r),
 | ||
| 		 uid_t user_id, struct passwd *pwd_r,
 | ||
| 		 char *buf_r, size_t len_r, struct passwd **pwd_entry)
 | ||
| {
 | ||
|   *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
 | ||
|   return (*pwd_entry == NULL) ? errno : 0;
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| /*
 | ||
|  * This method returns a time zone string that is used by init_properties
 | ||
|  * to set the default timezone property 'user.timezone'.  That value is
 | ||
|  * used by default as a key into the timezone table used by the
 | ||
|  * java::util::TimeZone class.
 | ||
|  */
 | ||
| jstring
 | ||
| java::lang::System::getSystemTimeZone (void)
 | ||
| {
 | ||
|   struct tm *tim;
 | ||
|   time_t current_time;
 | ||
|   char **tzinfo, *tzid;
 | ||
|   long tzoffset;
 | ||
| 
 | ||
|   current_time = time(0);
 | ||
| 
 | ||
|   mktime(tim = localtime(¤t_time));
 | ||
| #ifdef STRUCT_TM_HAS_GMTOFF
 | ||
|   tzoffset = -(tim->tm_gmtoff);	// tm_gmtoff is secs EAST of UTC.
 | ||
| #elif HAVE_TIMEZONE
 | ||
|   tzoffset = timezone;		// timezone is secs WEST of UTC.
 | ||
| #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.  Also note that this same
 | ||
|   // issue exists in java/util/natGregorianCalendar.cc.
 | ||
|   tzoffset = 0L;
 | ||
| #endif
 | ||
|   tzinfo = tzname;
 | ||
| 
 | ||
|   if ((tzoffset % 3600) == 0)
 | ||
|     tzoffset = tzoffset / 3600;
 | ||
| 
 | ||
|   if (!strcmp(tzinfo[0], tzinfo[1]))  
 | ||
|     {
 | ||
|       tzid = (char*) _Jv_Malloc (strlen(tzinfo[0]) + 6);
 | ||
|       if (!tzid)
 | ||
|         return NULL;
 | ||
| 
 | ||
|       sprintf(tzid, "%s%ld", tzinfo[0], tzoffset);
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       tzid = (char*) _Jv_Malloc (strlen(tzinfo[0]) + strlen(tzinfo[1]) + 6);
 | ||
|       if (!tzid)
 | ||
|         return NULL;
 | ||
| 
 | ||
|       sprintf(tzid, "%s%ld%s", tzinfo[0], tzoffset, tzinfo[1]);
 | ||
|     }
 | ||
| 
 | ||
|   jstring retval = JvNewStringUTF (tzid);
 | ||
|   _Jv_Free (tzid);
 | ||
|   return retval;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| java::lang::System::init_properties (void)
 | ||
| {
 | ||
|   JvSynchronize sync (&java::lang::System::class$);
 | ||
|   
 | ||
|   if (properties != NULL)
 | ||
|     return;
 | ||
| 
 | ||
|   java::util::Properties* newprops = new java::util::Properties ();
 | ||
|   
 | ||
|   // A convenience define.
 | ||
| #define SET(Prop,Val) \
 | ||
| 	newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
 | ||
| 
 | ||
|   // A mixture of the Java Product Versioning Specification
 | ||
|   // (introduced in 1.2), and earlier versioning properties.
 | ||
|   SET ("java.version", VERSION);
 | ||
|   SET ("java.vendor", "Free Software Foundation");
 | ||
|   SET ("java.vendor.url", "http://gcc.gnu.org/java/");
 | ||
|   SET ("java.class.version", GCJVERSION);
 | ||
|   SET ("java.vm.specification.version", "1.1");
 | ||
|   SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
 | ||
|   SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
 | ||
|   SET ("java.vm.version", GCJVERSION);
 | ||
|   SET ("java.vm.vendor", "Free Software Foundation");
 | ||
|   SET ("java.vm.name", "libgcj");
 | ||
|   SET ("java.specification.version", "1.1");
 | ||
|   SET ("java.specification.name", "Java(tm) Language Specification");
 | ||
|   SET ("java.specification.vendor", "Sun Microsystems Inc.");
 | ||
| 
 | ||
|   // FIXME: how to set this given location-independence?
 | ||
|   // SET ("java.home", "FIXME");
 | ||
|   
 | ||
|   SET ("file.encoding", default_file_encoding);
 | ||
| 
 | ||
| #ifdef WIN32
 | ||
|   SET ("file.separator", "\\");
 | ||
|   SET ("path.separator", ";");
 | ||
|   SET ("line.separator", "\r\n");
 | ||
|   SET ("java.io.tmpdir", "C:\\temp");
 | ||
| #else
 | ||
|   // Unix.
 | ||
|   SET ("file.separator", "/");
 | ||
|   SET ("path.separator", ":");
 | ||
|   SET ("line.separator", "\n");
 | ||
|   char *tmpdir = ::getenv("TMPDIR");
 | ||
|   if (! tmpdir)
 | ||
|     tmpdir = "/tmp";
 | ||
|   SET ("java.io.tmpdir", tmpdir);
 | ||
| #endif
 | ||
| 
 | ||
| #ifdef HAVE_UNAME
 | ||
|   struct utsname u;
 | ||
|   if (! uname (&u))
 | ||
|     {
 | ||
|       SET ("os.name", u.sysname);
 | ||
|       SET ("os.arch", u.machine);
 | ||
|       SET ("os.version", u.release);
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       SET ("os.name", "unknown");
 | ||
|       SET ("os.arch", "unknown");
 | ||
|       SET ("os.version", "unknown");
 | ||
|     }
 | ||
| #endif /* HAVE_UNAME */
 | ||
| 
 | ||
| #ifndef NO_GETUID
 | ||
| #ifdef HAVE_PWD_H
 | ||
|   uid_t user_id = getuid ();
 | ||
|   struct passwd *pwd_entry;
 | ||
| 
 | ||
| #ifdef HAVE_GETPWUID_R
 | ||
|   struct passwd pwd_r;
 | ||
|   size_t len_r = 200;
 | ||
|   char *buf_r = (char *) _Jv_AllocBytes (len_r);
 | ||
| 
 | ||
|   while (buf_r != NULL)
 | ||
|     {
 | ||
|       int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
 | ||
| 				buf_r, len_r, &pwd_entry);
 | ||
|       if (r == 0)
 | ||
| 	break;
 | ||
|       else if (r != ERANGE)
 | ||
| 	{
 | ||
| 	  pwd_entry = NULL;
 | ||
| 	  break;
 | ||
| 	}
 | ||
|       len_r *= 2;
 | ||
|       buf_r = (char *) _Jv_AllocBytes (len_r);
 | ||
|     }
 | ||
| #else
 | ||
|   pwd_entry = getpwuid (user_id);
 | ||
| #endif /* HAVE_GETPWUID_R */
 | ||
| 
 | ||
|   if (pwd_entry != NULL)
 | ||
|     {
 | ||
|       SET ("user.name", pwd_entry->pw_name);
 | ||
|       SET ("user.home", pwd_entry->pw_dir);
 | ||
|     }
 | ||
| #endif /* HAVE_PWD_H */
 | ||
| #endif /* NO_GETUID */
 | ||
| 
 | ||
| #ifdef HAVE_GETCWD
 | ||
| #ifdef HAVE_UNISTD_H
 | ||
|   /* Use getcwd to set "user.dir". */
 | ||
|   int buflen = 250;
 | ||
|   char *buffer = (char *) malloc (buflen);
 | ||
|   while (buffer != NULL)
 | ||
|     {
 | ||
|       if (getcwd (buffer, buflen) != NULL)
 | ||
| 	{
 | ||
| 	  SET ("user.dir", buffer);
 | ||
| 	  break;
 | ||
| 	}
 | ||
|       if (errno != ERANGE)
 | ||
| 	break;
 | ||
|       buflen = 2 * buflen;
 | ||
|       buffer = (char *) realloc (buffer, buflen);
 | ||
|     }
 | ||
|   if (buffer != NULL)
 | ||
|     free (buffer);
 | ||
| #endif /* HAVE_UNISTD_H */
 | ||
| #endif /* HAVE_GETCWD */
 | ||
| 
 | ||
|   // Set user locale properties based on setlocale()
 | ||
| #ifdef HAVE_SETLOCALE
 | ||
|   char *locale = setlocale (LC_ALL, "");
 | ||
|   if (locale && strlen (locale) >= 2)
 | ||
|     {
 | ||
|       char buf[3];
 | ||
|       buf[2] = '\0';
 | ||
|       // copy the first two chars to user.language
 | ||
|       strncpy (buf, locale, 2);
 | ||
|       SET ("user.language", buf);
 | ||
|       // if the next char is a '_', copy the two after that to user.region
 | ||
|       locale += 2;
 | ||
|       if (locale[0] == '_')
 | ||
|         {
 | ||
| 	  locale++;
 | ||
| 	  strncpy (buf, locale, 2);
 | ||
| 	  SET ("user.region", buf);
 | ||
|         }
 | ||
|     }
 | ||
|   else
 | ||
| #endif /* HAVE_SETLOCALE */
 | ||
|     {
 | ||
|       SET ("user.language", "en");
 | ||
|     }  
 | ||
| 
 | ||
|   // Set the "user.timezone" property.
 | ||
|   jstring timezone = getDefaultTimeZoneId ();
 | ||
|   if (timezone != NULL)
 | ||
|     newprops->put (JvNewStringLatin1 ("user.timezone"), timezone);
 | ||
| 
 | ||
|   // Set some properties according to whatever was compiled in with
 | ||
|   // `-D'.
 | ||
|   for (int i = 0; _Jv_Compiler_Properties[i]; ++i)
 | ||
|     {
 | ||
|       const char *s, *p;
 | ||
|       // Find the `='.
 | ||
|       for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
 | ||
| 	;
 | ||
|       jstring name = JvNewStringLatin1 (p, s - p);
 | ||
|       jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
 | ||
|       newprops->put (name, val);
 | ||
|     }
 | ||
| 
 | ||
|   // Set the system properties from the user's environment.
 | ||
|   if (_Jv_Environment_Properties)
 | ||
|     {
 | ||
|       size_t i = 0;
 | ||
| 
 | ||
|       while (_Jv_Environment_Properties[i].key)
 | ||
| 	{
 | ||
| 	  SET (_Jv_Environment_Properties[i].key, 
 | ||
| 	       _Jv_Environment_Properties[i].value);
 | ||
| 	  i++;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   if (_Jv_Jar_Class_Path)
 | ||
|     newprops->put(JvNewStringLatin1 ("java.class.path"),
 | ||
| 		  JvNewStringLatin1 (_Jv_Jar_Class_Path));
 | ||
|   else
 | ||
|     {
 | ||
|       // FIXME: find libgcj.zip and append its path?
 | ||
|       char *classpath = ::getenv("CLASSPATH");
 | ||
|       jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
 | ||
|       java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
 | ||
|       
 | ||
|       if (classpath)
 | ||
| 	{
 | ||
| 	  sb->append (JvNewStringLatin1 (classpath));
 | ||
| #ifdef WIN32
 | ||
| 	  sb->append ((jchar) ';');
 | ||
| #else
 | ||
| 	  sb->append ((jchar) ':');
 | ||
| #endif
 | ||
| 	}
 | ||
|       if (cp != NULL)
 | ||
| 	sb->append (cp);
 | ||
|       else
 | ||
| 	sb->append ((jchar) '.');
 | ||
|       
 | ||
|       newprops->put(JvNewStringLatin1 ("java.class.path"),
 | ||
| 		      sb->toString ());
 | ||
|     }
 | ||
|   // Finally, set the field. This ensures that concurrent getProperty() 
 | ||
|   // calls will return initialized values without requiring them to be 
 | ||
|   // synchronized in the common case.
 | ||
|   properties = newprops;
 | ||
| }
 |