OSDN Git Service

2006-07-04 Andreas Tobler <a.tobler@schweiz.ch>
[pf3gnuchains/gcc-fork.git] / libjava / win32.cc
index abe768a..00b4279 100644 (file)
@@ -1,6 +1,6 @@
 // win32.cc - Helper functions for Microsoft-flavored OSs.
 
-/* Copyright (C) 2002, 2003  Free Software Foundation
+/* Copyright (C) 2002, 2003, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -12,6 +12,10 @@ details.  */
 #include <platform.h>
 #include <sys/timeb.h>
 #include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <java-stack.h>
 
 #include <java/lang/ArithmeticException.h>
 #include <java/lang/UnsupportedOperationException.h>
@@ -41,12 +45,125 @@ const char *_Jv_ThisExecutable (void)
 
 // Helper classes and methods implementation
   
+#ifdef MINGW_LIBGCJ_UNICODE
+
+// We're using the OS W (UNICODE) API, which means that we're speaking
+// the same language....
+jstring
+_Jv_Win32NewString (LPCTSTR pcsz)
+{
+  return JvNewString ((jchar*) pcsz, _tcslen (pcsz));
+}
+
+#else
+
+// We're using the OS A functions, which means we need to translate between
+// UNICODE and the native character set.
+
+// First, let's set up some helper translation functions....
+
+// Converts the native string to any specified jstring, returning the
+// length of the jstring. If the specified jstring is null, we simply
+// compute and return the length.
+static int nativeToUnicode(LPCSTR pcsz, jstring jstr = 0)
+{
+  jchar* buf = 0;
+  int len = 0;
+  if (jstr)
+    {
+      len = jstr->length();
+      buf = JvGetStringChars(jstr);
+    }
+  return ::MultiByteToWideChar(GetACP(), 0, pcsz,
+    strlen(pcsz), (LPWSTR) buf, len);
+}
+
+// Does the inverse of nativeToUnicode, with the same calling semantics.
+static int unicodeToNative(jstring jstr, LPSTR buf, int buflen)
+{
+  return ::WideCharToMultiByte(GetACP(), 0, (LPWSTR) JvGetStringChars(jstr),
+    jstr->length(), buf, buflen, NULL, NULL);
+}
+
+// Convenience function when the caller only wants to compute the length
+// of the native string.
+static int unicodeToNative(jstring jstr)
+{
+  return unicodeToNative(jstr, 0, 0);
+}
+
+jstring
+_Jv_Win32NewString (LPCTSTR pcsz)
+{
+  // Compute the length, allocate the jstring, then perform the conversion.
+  int len = nativeToUnicode(pcsz);
+  jstring jstr = JvAllocString(len);
+  nativeToUnicode(pcsz, jstr);
+  return jstr;
+}
+
+#endif // MINGW_LIBGCJ_UNICODE
+
+// class _Jv_Win32TempString
+_Jv_Win32TempString::_Jv_Win32TempString(jstring jstr):
+  buf_(0)
+{
+  if (jstr == 0)
+    return;
+    
+  // We need space for the string length plus a null terminator.
+  // Determine whether to use our stack-allocated buffer or a heap-
+  // allocated one.
+#ifdef MINGW_LIBGCJ_UNICODE
+  // A UNICODE character is a UNICODE character is a UNICODE character....
+  int len = jstr->length();
+#else
+  // Compute the length of the native character string.
+  int len = unicodeToNative(jstr);
+#endif // MINGW_LIBGCJ_UNICODE
+
+  int bytesNeeded = (len + 1) * sizeof(TCHAR);
+  if (bytesNeeded <= (int) sizeof(stackbuf_))
+    buf_ = stackbuf_;
+  else
+    buf_ = (LPTSTR) _Jv_Malloc(bytesNeeded);
+    
+#ifdef MINGW_LIBGCJ_UNICODE
+  // Copy the UNICODE characters to our buffer.
+  _tcsncpy(buf_, (LPCTSTR) JvGetStringChars (jstr), len);
+#else
+  // Convert the UNICODE string to a native one.
+  unicodeToNative(jstr, buf_, len);
+#endif // MINGW_LIBGCJ_UNICODE
+
+  buf_[len] = 0;
+}
+
+_Jv_Win32TempString::~_Jv_Win32TempString()
+{
+  if (buf_ && buf_ != stackbuf_)
+    _Jv_Free (buf_);
+}
+
 // class WSAEventWrapper
+WSAEventWrapper::WSAEventWrapper ():
+  m_hEvent(0),
+  m_fd(0),
+  m_dwSelFlags(0)
+{}
+
 WSAEventWrapper::WSAEventWrapper (int fd, DWORD dwSelFlags):
   m_hEvent(0),
-  m_fd(fd),
-  m_dwSelFlags(dwSelFlags)
+  m_fd(0),
+  m_dwSelFlags(0)
 {
+  init(fd, dwSelFlags);
+}
+
+void WSAEventWrapper::init(int fd, DWORD dwSelFlags)
+{
+  m_fd = fd;
+  m_dwSelFlags = dwSelFlags;
   m_hEvent = WSACreateEvent ();
   if (dwSelFlags)
     WSAEventSelect(fd, m_hEvent, dwSelFlags);
@@ -91,16 +208,17 @@ _Jv_WinStrError (LPCTSTR lpszPrologue, int nErrorCode)
   if (lpszPrologue)
     {
       LPTSTR lpszTemp =
-        (LPTSTR) _Jv_Malloc (strlen (lpszPrologue) +
-          strlen (lpMsgBuf) + 3);
-      strcpy (lpszTemp, lpszPrologue);
-      strcat (lpszTemp, ": ");
-      strcat (lpszTemp, lpMsgBuf);
-      ret = JvNewStringLatin1 (lpszTemp);
+        (LPTSTR) _Jv_Malloc ((_tcslen (lpszPrologue) +
+          _tcslen (lpMsgBuf) + 3) * sizeof(TCHAR) );
+      _tcscpy (lpszTemp, lpszPrologue);
+      _tcscat (lpszTemp, _T(": "));
+      _tcscat (lpszTemp, lpMsgBuf);
+      ret = _Jv_Win32NewString (lpszTemp);
+      _Jv_Free (lpszTemp);
     } 
   else
     {
-      ret = JvNewStringLatin1 (lpMsgBuf);
+      ret = _Jv_Win32NewString (lpMsgBuf);
     }
 
   LocalFree(lpMsgBuf);
@@ -141,15 +259,18 @@ _Jv_platform_initialize (void)
 {
   // Initialise winsock for networking
   WSADATA data;
-  if (WSAStartup (MAKEWORD (1, 1), &data))
-    MessageBox (NULL, "Error initialising winsock library.", "Error",
+  if (WSAStartup (MAKEWORD (2, 2), &data))
+    MessageBox (NULL, _T("Error initialising winsock library."), _T("Error"),
     MB_OK | MB_ICONEXCLAMATION);
 
   // Install exception handler
   SetUnhandledExceptionFilter (win32_exception_handler);
 
-  // Initialize our executable name
-  GetModuleFileName(NULL, exec_name, sizeof(exec_name));
+  // Initialize our executable name.
+  // FIXME: We unconditionally use the ANSI function because
+  // _Jv_ThisExecutable returns a const char*. We should really
+  // change _Jv_ThisExecutable to return a jstring.
+  GetModuleFileNameA(NULL, exec_name, sizeof(exec_name));
 }
 
 // gettimeofday implementation.
@@ -161,6 +282,12 @@ _Jv_platform_gettimeofday ()
   return t.time * 1000LL + t.millitm;
 }
 
+jlong
+_Jv_platform_nanotime ()
+{
+  return _Jv_platform_gettimeofday () * 1000LL;
+}
+
 // The following definitions "fake out" mingw to think that -mthreads
 // was enabled and that mingwthr.dll was linked. GCJ-compiled
 // applications don't need this helper library because we can safely
@@ -176,21 +303,58 @@ __mingwthr_key_dtor (DWORD, void (*) (void *))
   return 0;
 }
 
+static bool dirExists (LPCTSTR dir)
+{
+  DWORD dwAttrs = ::GetFileAttributes (dir);
+  return dwAttrs != 0xFFFFFFFF &&
+    (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+static void getUserHome(LPTSTR userHome, LPCTSTR userId)
+{
+  LPTSTR uh = _tgetenv (_T("USERPROFILE"));
+  if (uh)
+    {
+      _tcscpy(userHome, uh);
+    }
+  else
+    {
+      // Make a half-hearted attempt to support this
+      // legacy version of Windows. Try %WINDIR%\Profiles\%USERNAME%
+      // and failing this, use %WINDIR%.
+      //
+      // See:http://java.sun.com/docs/books/tutorial/security1.2/summary/files.html#UserPolicy
+      //
+      // To do this correctly, we'd have to factor in the
+      // Windows version, but if we did that, then this attempt
+      // wouldn't be half-hearted.
+      TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH];
+      ::GetWindowsDirectory(winHome, MAX_PATH);
+        // assume this call always succeeds
+
+      _stprintf(userHomePath, _T("%s\\Profiles\\%s"), winHome, userId);
+      if (dirExists (userHomePath))
+        _tcscpy(userHome, userHomePath);
+      else
+        _tcscpy(userHome, winHome);
+    }
+}
+
 // Set platform-specific System properties.
 void
 _Jv_platform_initProperties (java::util::Properties* newprops)
 {
   // A convenience define.
 #define SET(Prop,Val) \
-  newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
+  newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val))
 
-  SET ("file.separator", "\\");
-  SET ("path.separator", ";");
-  SET ("line.separator", "\r\n");
+  SET ("file.separator", _T("\\"));
+  SET ("path.separator", _T(";"));
+  SET ("line.separator", _T("\r\n"));
 
   // Use GetCurrentDirectory to set 'user.dir'.
   DWORD buflen = MAX_PATH;
-  char *buffer = (char *) _Jv_MallocUnchecked (buflen);
+  TCHAR buffer[buflen];
   if (buffer != NULL)
     {
       if (GetCurrentDirectory (buflen, buffer))
@@ -198,43 +362,18 @@ _Jv_platform_initProperties (java::util::Properties* newprops)
 
       if (GetTempPath (buflen, buffer))
   SET ("java.io.tmpdir", buffer);
-
-      _Jv_Free (buffer);
     }
 
   // Use GetUserName to set 'user.name'.
   buflen = 257;  // UNLEN + 1
-  buffer = (char *) _Jv_MallocUnchecked (buflen);
-  if (buffer != NULL)
-    {
-      if (GetUserName (buffer, &buflen))
-        SET ("user.name", buffer);
-      _Jv_Free (buffer);
-    }
+  TCHAR userName[buflen];
+  if (GetUserName (userName, &buflen))
+    SET ("user.name", userName);
 
-  // According to the api documentation for 'GetWindowsDirectory()', the
-  // environmental variable HOMEPATH always specifies the user's home
-  // directory or a default directory.  On the 3 windows machines I checked
-  // only 1 had it set.  If it's not set, JDK1.3.1 seems to set it to
-  // the windows directory, so we'll do the same.
-  char *userHome = NULL;
-  if ((userHome = ::getenv ("HOMEPATH")) == NULL )
-    {
-      // Check HOME since it's what I use.
-      if ((userHome = ::getenv ("HOME")) == NULL )
-        {
-          // Not found - use the windows directory like JDK1.3.1 does.
-          char *winHome = (char *) _Jv_MallocUnchecked (MAX_PATH);
-          if (winHome != NULL)
-            {
-              if (GetWindowsDirectory (winHome, MAX_PATH))
-        SET ("user.home", winHome);
-              _Jv_Free (winHome);
-            }
-        }
-     }
-  if (userHome != NULL)
-    SET ("user.home", userHome);
+  // Set user.home
+  TCHAR userHome[MAX_PATH];
+  getUserHome(userHome, userName);
+  SET ("user.home", userHome);
 
   // Get and set some OS info.
   OSVERSIONINFO osvi;
@@ -242,41 +381,39 @@ _Jv_platform_initProperties (java::util::Properties* newprops)
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
   if (GetVersionEx (&osvi))
     {
-      char *buffer = (char *) _Jv_MallocUnchecked (30);
       if (buffer != NULL)
         {
-          sprintf (buffer, "%d.%d", (int) osvi.dwMajorVersion,
+          _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion,
            (int) osvi.dwMinorVersion);
           SET ("os.version", buffer);
-          _Jv_Free (buffer);
         }
 
       switch (osvi.dwPlatformId)
         {
           case VER_PLATFORM_WIN32_WINDOWS:
             if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
-              SET ("os.name", "Windows 95");
+              SET ("os.name", _T("Windows 95"));
             else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
-              SET ("os.name", "Windows 98");
+              SET ("os.name", _T("Windows 98"));
             else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
-              SET ("os.name", "Windows Me");
+              SET ("os.name", _T("Windows Me"));
             else
-              SET ("os.name", "Windows ??");
+              SET ("os.name", _T("Windows ??"));
             break;
 
           case VER_PLATFORM_WIN32_NT:
             if (osvi.dwMajorVersion <= 4 )
-              SET ("os.name", "Windows NT");
+              SET ("os.name", _T("Windows NT"));
             else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
-              SET ("os.name", "Windows 2000");
+              SET ("os.name", _T("Windows 2000"));
             else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
-              SET ("os.name", "Windows XP");
+              SET ("os.name", _T("Windows XP"));
             else
-              SET ("os.name", "Windows NT ??");
+              SET ("os.name", _T("Windows NT ??"));
             break;
 
           default:
-            SET ("os.name", "Windows UNKNOWN");
+            SET ("os.name", _T("Windows UNKNOWN"));
             break;
        }
   }
@@ -287,58 +424,76 @@ _Jv_platform_initProperties (java::util::Properties* newprops)
   switch (si.wProcessorArchitecture)
     {
       case PROCESSOR_ARCHITECTURE_INTEL:
-        SET ("os.arch", "x86");
+        SET ("os.arch", _T("x86"));
         break;
       case PROCESSOR_ARCHITECTURE_MIPS:
-        SET ("os.arch", "mips");
+        SET ("os.arch", _T("mips"));
         break;
       case PROCESSOR_ARCHITECTURE_ALPHA:
-        SET ("os.arch", "alpha");
+        SET ("os.arch", _T("alpha"));
         break;
-      case PROCESSOR_ARCHITECTURE_PPC: 
-        SET ("os.arch", "ppc");
+      case PROCESSOR_ARCHITECTURE_PPC:  
+        SET ("os.arch", _T("ppc"));
         break;
       case PROCESSOR_ARCHITECTURE_IA64:
-        SET ("os.arch", "ia64");
+        SET ("os.arch", _T("ia64"));
         break;
       case PROCESSOR_ARCHITECTURE_UNKNOWN:
       default:
-        SET ("os.arch", "unknown");
+        SET ("os.arch", _T("unknown"));
         break;
     }
 }
 
-/* Store up to SIZE return address of the current program state in
-   ARRAY and return the exact number of values stored.  */
 int
-backtrace (void **__array, int __size)
+_Jv_pipe (int filedes[2])
 {
-  register void *_ebp __asm__ ("ebp");
-  register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
-
-  int i=0;
-  for (rfp = *(unsigned int**)_ebp;
-       rfp && i < __size;
-       rfp = *(unsigned int **)rfp)
-    {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break;
+  return _pipe (filedes, 4096, _O_BINARY);
+}
 
-    __array[i++] = (void*)(rfp[1]-4);
-  }
-  return i;
+void
+_Jv_platform_close_on_exec (HANDLE h)
+{
+  // Mark the handle as non-inheritable. This has
+  // no effect under Win9X.
+  SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
 }
 
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
 int
-_Jv_select (int n, fd_set *readfds, fd_set  *writefds,
-      fd_set *exceptfds, struct timeval *timeout)
+_Jv_platform_dladdr (void *addr, _Jv_AddrInfo *info)
 {
-  int r = ::select (n, readfds, writefds, exceptfds, timeout);
-  if (r == SOCKET_ERROR)
-    {
-      DWORD dwErrorCode = WSAGetLastError ();
-      throw new java::io::IOException (_Jv_WinStrError (dwErrorCode));
-    }
-  return r;      
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+  if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
+  {
+    return 0;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return 0;
+  }
+
+  char *file_name = (char *)(malloc (strlen (moduleName) + 1));
+  strcpy (file_name, moduleName);
+  info->file_name = file_name;
+
+  // FIXME.
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+
+  return 1;
 }