OSDN Git Service

* rtl.def (LABEL_REF): Remove the field for LABEL_NEXTREF.
[pf3gnuchains/gcc-fork.git] / libjava / win32.cc
1 // win32.cc - Helper functions for Microsoft-flavored OSs.
2
3 /* Copyright (C) 2002, 2003, 2006  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12 #include <platform.h>
13 #include <sys/timeb.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16
17 #include <java/lang/ArithmeticException.h>
18 #include <java/lang/UnsupportedOperationException.h>
19 #include <java/io/IOException.h>
20 #include <java/net/SocketException.h>
21 #include <java/util/Properties.h>
22
23 static LONG CALLBACK
24 win32_exception_handler (LPEXCEPTION_POINTERS e)
25 {
26   if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
27     _Jv_ThrowNullPointerException();
28   else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
29     throw new java::lang::ArithmeticException;
30   else
31     return EXCEPTION_CONTINUE_SEARCH;
32 }
33
34 // Platform-specific executable name
35 static char exec_name[MAX_PATH];
36   // initialized in _Jv_platform_initialize()
37
38 const char *_Jv_ThisExecutable (void)
39 {
40   return exec_name;
41 }
42
43 // Helper classes and methods implementation
44   
45 #ifdef MINGW_LIBGCJ_UNICODE
46
47 // We're using the OS W (UNICODE) API, which means that we're speaking
48 // the same language....
49 jstring
50 _Jv_Win32NewString (LPCTSTR pcsz)
51 {
52   return JvNewString ((jchar*) pcsz, _tcslen (pcsz));
53 }
54
55 #else
56
57 // We're using the OS A functions, which means we need to translate between
58 // UNICODE and the native character set.
59
60 // First, let's set up some helper translation functions....
61
62 // Converts the native string to any specified jstring, returning the
63 // length of the jstring. If the specified jstring is null, we simply
64 // compute and return the length.
65 static int nativeToUnicode(LPCSTR pcsz, jstring jstr = 0)
66 {
67   jchar* buf = 0;
68   int len = 0;
69   if (jstr)
70     {
71       len = jstr->length();
72       buf = JvGetStringChars(jstr);
73     }
74   return ::MultiByteToWideChar(GetACP(), 0, pcsz,
75     strlen(pcsz), (LPWSTR) buf, len);
76 }
77
78 // Does the inverse of nativeToUnicode, with the same calling semantics.
79 static int unicodeToNative(jstring jstr, LPSTR buf, int buflen)
80 {
81   return ::WideCharToMultiByte(GetACP(), 0, (LPWSTR) JvGetStringChars(jstr),
82     jstr->length(), buf, buflen, NULL, NULL);
83 }
84
85 // Convenience function when the caller only wants to compute the length
86 // of the native string.
87 static int unicodeToNative(jstring jstr)
88 {
89   return unicodeToNative(jstr, 0, 0);
90 }
91
92 jstring
93 _Jv_Win32NewString (LPCTSTR pcsz)
94 {
95   // Compute the length, allocate the jstring, then perform the conversion.
96   int len = nativeToUnicode(pcsz);
97   jstring jstr = JvAllocString(len);
98   nativeToUnicode(pcsz, jstr);
99   return jstr;
100 }
101
102 #endif // MINGW_LIBGCJ_UNICODE
103
104 // class _Jv_Win32TempString
105 _Jv_Win32TempString::_Jv_Win32TempString(jstring jstr):
106   buf_(0)
107 {
108   if (jstr == 0)
109     return;
110     
111   // We need space for the string length plus a null terminator.
112   // Determine whether to use our stack-allocated buffer or a heap-
113   // allocated one.
114 #ifdef MINGW_LIBGCJ_UNICODE
115   // A UNICODE character is a UNICODE character is a UNICODE character....
116   int len = jstr->length();
117 #else
118   // Compute the length of the native character string.
119   int len = unicodeToNative(jstr);
120 #endif // MINGW_LIBGCJ_UNICODE
121
122   int bytesNeeded = (len + 1) * sizeof(TCHAR);
123   if (bytesNeeded <= (int) sizeof(stackbuf_))
124     buf_ = stackbuf_;
125   else
126     buf_ = (LPTSTR) _Jv_Malloc(bytesNeeded);
127     
128 #ifdef MINGW_LIBGCJ_UNICODE
129   // Copy the UNICODE characters to our buffer.
130   _tcsncpy(buf_, (LPCTSTR) JvGetStringChars (jstr), len);
131 #else
132   // Convert the UNICODE string to a native one.
133   unicodeToNative(jstr, buf_, len);
134 #endif // MINGW_LIBGCJ_UNICODE
135
136   buf_[len] = 0;
137 }
138
139 _Jv_Win32TempString::~_Jv_Win32TempString()
140 {
141   if (buf_ && buf_ != stackbuf_)
142     _Jv_Free (buf_);
143 }
144
145 // class WSAEventWrapper
146 WSAEventWrapper::WSAEventWrapper ():
147   m_hEvent(0),
148   m_fd(0),
149   m_dwSelFlags(0)
150 {}
151
152 WSAEventWrapper::WSAEventWrapper (int fd, DWORD dwSelFlags):
153   m_hEvent(0),
154   m_fd(0),
155   m_dwSelFlags(0)
156 {
157   init(fd, dwSelFlags);
158 }
159
160 void WSAEventWrapper::init(int fd, DWORD dwSelFlags)
161 {
162   m_fd = fd;
163   m_dwSelFlags = dwSelFlags;
164   m_hEvent = WSACreateEvent ();
165   if (dwSelFlags)
166     WSAEventSelect(fd, m_hEvent, dwSelFlags);
167 }
168
169 WSAEventWrapper::~WSAEventWrapper ()
170 {
171   if (m_dwSelFlags)
172   {
173     WSAEventSelect(m_fd, m_hEvent, 0);
174     if (m_dwSelFlags & (FD_ACCEPT | FD_CONNECT))
175     {
176       // Set the socket back to non-blocking mode.
177       // Ignore any error since we're in a destructor.
178       unsigned long lSockOpt = 0L;
179         // blocking mode
180       ::ioctlsocket (m_fd, FIONBIO, &lSockOpt);
181     }
182   }
183   WSACloseEvent (m_hEvent);
184 }
185
186 // Error string text.
187 jstring
188 _Jv_WinStrError (LPCTSTR lpszPrologue, int nErrorCode)
189 {
190   LPTSTR lpMsgBuf = 0;
191
192   DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
193     FORMAT_MESSAGE_FROM_SYSTEM |
194     FORMAT_MESSAGE_IGNORE_INSERTS;
195
196   FormatMessage (dwFlags,
197     NULL,
198     (DWORD) nErrorCode,
199     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
200     (LPTSTR) &lpMsgBuf,
201     0,
202     NULL);
203
204   jstring ret;
205   if (lpszPrologue)
206     {
207       LPTSTR lpszTemp =
208         (LPTSTR) _Jv_Malloc ((_tcslen (lpszPrologue) +
209           _tcslen (lpMsgBuf) + 3) * sizeof(TCHAR) );
210       _tcscpy (lpszTemp, lpszPrologue);
211       _tcscat (lpszTemp, _T(": "));
212       _tcscat (lpszTemp, lpMsgBuf);
213       ret = _Jv_Win32NewString (lpszTemp);
214       _Jv_Free (lpszTemp);
215     } 
216   else
217     {
218       ret = _Jv_Win32NewString (lpMsgBuf);
219     }
220
221   LocalFree(lpMsgBuf);
222   return ret;
223 }
224
225 jstring
226 _Jv_WinStrError (int nErrorCode)
227 {
228   return _Jv_WinStrError (0, nErrorCode);
229 }
230
231 void _Jv_ThrowIOException (DWORD dwErrorCode)
232 {
233   throw new java::io::IOException (_Jv_WinStrError (dwErrorCode));
234 }
235
236 void _Jv_ThrowIOException()
237 {
238   DWORD dwErrorCode = WSAGetLastError ();
239   _Jv_ThrowIOException (dwErrorCode);
240 }
241
242 void _Jv_ThrowSocketException (DWORD dwErrorCode)
243 {
244   throw new java::net::SocketException (_Jv_WinStrError (dwErrorCode));
245 }
246
247 void _Jv_ThrowSocketException()
248 {
249   DWORD dwErrorCode = WSAGetLastError ();
250   _Jv_ThrowSocketException (dwErrorCode);
251 }
252
253 // Platform-specific VM initialization.
254 void
255 _Jv_platform_initialize (void)
256 {
257   // Initialise winsock for networking
258   WSADATA data;
259   if (WSAStartup (MAKEWORD (2, 2), &data))
260     MessageBox (NULL, _T("Error initialising winsock library."), _T("Error"),
261     MB_OK | MB_ICONEXCLAMATION);
262
263   // Install exception handler
264   SetUnhandledExceptionFilter (win32_exception_handler);
265
266   // Initialize our executable name.
267   // FIXME: We unconditionally use the ANSI function because
268   // _Jv_ThisExecutable returns a const char*. We should really
269   // change _Jv_ThisExecutable to return a jstring.
270   GetModuleFileNameA(NULL, exec_name, sizeof(exec_name));
271 }
272
273 // gettimeofday implementation.
274 jlong
275 _Jv_platform_gettimeofday ()
276 {
277   struct timeb t;
278   ftime (&t);
279   return t.time * 1000LL + t.millitm;
280 }
281
282 jlong
283 _Jv_platform_nanotime ()
284 {
285   return _Jv_platform_gettimeofday () * 1000LL;
286 }
287
288 // The following definitions "fake out" mingw to think that -mthreads
289 // was enabled and that mingwthr.dll was linked. GCJ-compiled
290 // applications don't need this helper library because we can safely
291 // detect thread death (return from Thread.run()).
292
293 int _CRT_MT = 1;
294
295 extern "C" int
296 __mingwthr_key_dtor (DWORD, void (*) (void *))
297 {
298   // FIXME: for now we do nothing; this causes a memory leak of
299   //        approximately 24 bytes per thread created.
300   return 0;
301 }
302
303 static bool dirExists (LPCTSTR dir)
304 {
305   DWORD dwAttrs = ::GetFileAttributes (dir);
306   return dwAttrs != 0xFFFFFFFF &&
307     (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
308 }
309
310 static void getUserHome(LPTSTR userHome, LPCTSTR userId)
311 {
312   LPTSTR uh = _tgetenv (_T("USERPROFILE"));
313   if (uh)
314     {
315       _tcscpy(userHome, uh);
316     }
317   else
318     {
319       // Make a half-hearted attempt to support this
320       // legacy version of Windows. Try %WINDIR%\Profiles\%USERNAME%
321       // and failing this, use %WINDIR%.
322       //
323       // See:http://java.sun.com/docs/books/tutorial/security1.2/summary/files.html#UserPolicy
324       //
325       // To do this correctly, we'd have to factor in the
326       // Windows version, but if we did that, then this attempt
327       // wouldn't be half-hearted.
328       TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH];
329       ::GetWindowsDirectory(winHome, MAX_PATH);
330         // assume this call always succeeds
331
332       _stprintf(userHomePath, _T("%s\\Profiles\\%s"), winHome, userId);
333       if (dirExists (userHomePath))
334         _tcscpy(userHome, userHomePath);
335       else
336         _tcscpy(userHome, winHome);
337     }
338 }
339
340 // Set platform-specific System properties.
341 void
342 _Jv_platform_initProperties (java::util::Properties* newprops)
343 {
344   // A convenience define.
345 #define SET(Prop,Val) \
346   newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val))
347
348   SET ("file.separator", _T("\\"));
349   SET ("path.separator", _T(";"));
350   SET ("line.separator", _T("\r\n"));
351
352   // Use GetCurrentDirectory to set 'user.dir'.
353   DWORD buflen = MAX_PATH;
354   TCHAR buffer[buflen];
355   if (buffer != NULL)
356     {
357       if (GetCurrentDirectory (buflen, buffer))
358   SET ("user.dir", buffer);
359
360       if (GetTempPath (buflen, buffer))
361   SET ("java.io.tmpdir", buffer);
362     }
363
364   // Use GetUserName to set 'user.name'.
365   buflen = 257;  // UNLEN + 1
366   TCHAR userName[buflen];
367   if (GetUserName (userName, &buflen))
368     SET ("user.name", userName);
369
370   // Set user.home
371   TCHAR userHome[MAX_PATH];
372   getUserHome(userHome, userName);
373   SET ("user.home", userHome);
374
375   // Get and set some OS info.
376   OSVERSIONINFO osvi;
377   ZeroMemory (&osvi, sizeof(OSVERSIONINFO));
378   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
379   if (GetVersionEx (&osvi))
380     {
381       if (buffer != NULL)
382         {
383           _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion,
384            (int) osvi.dwMinorVersion);
385           SET ("os.version", buffer);
386         }
387
388       switch (osvi.dwPlatformId)
389         {
390           case VER_PLATFORM_WIN32_WINDOWS:
391             if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
392               SET ("os.name", _T("Windows 95"));
393             else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
394               SET ("os.name", _T("Windows 98"));
395             else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
396               SET ("os.name", _T("Windows Me"));
397             else
398               SET ("os.name", _T("Windows ??"));
399             break;
400
401           case VER_PLATFORM_WIN32_NT:
402             if (osvi.dwMajorVersion <= 4 )
403               SET ("os.name", _T("Windows NT"));
404             else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
405               SET ("os.name", _T("Windows 2000"));
406             else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
407               SET ("os.name", _T("Windows XP"));
408             else
409               SET ("os.name", _T("Windows NT ??"));
410             break;
411
412           default:
413             SET ("os.name", _T("Windows UNKNOWN"));
414             break;
415        }
416   }
417
418   // Set the OS architecture.
419   SYSTEM_INFO si;
420   GetSystemInfo (&si);
421   switch (si.wProcessorArchitecture)
422     {
423       case PROCESSOR_ARCHITECTURE_INTEL:
424         SET ("os.arch", _T("x86"));
425         break;
426       case PROCESSOR_ARCHITECTURE_MIPS:
427         SET ("os.arch", _T("mips"));
428         break;
429       case PROCESSOR_ARCHITECTURE_ALPHA:
430         SET ("os.arch", _T("alpha"));
431         break;
432       case PROCESSOR_ARCHITECTURE_PPC:  
433         SET ("os.arch", _T("ppc"));
434         break;
435       case PROCESSOR_ARCHITECTURE_IA64:
436         SET ("os.arch", _T("ia64"));
437         break;
438       case PROCESSOR_ARCHITECTURE_UNKNOWN:
439       default:
440         SET ("os.arch", _T("unknown"));
441         break;
442     }
443 }
444
445 /* Store up to SIZE return address of the current program state in
446    ARRAY and return the exact number of values stored.  */
447 int
448 backtrace (void **__array, int __size)
449 {
450   register void *_ebp __asm__ ("ebp");
451   register void *_esp __asm__ ("esp");
452   unsigned int *rfp;
453
454   int i=0;
455   for (rfp = *(unsigned int**)_ebp;
456        rfp && i < __size;
457        rfp = *(unsigned int **)rfp)
458     {
459       int diff = *rfp - (unsigned int)rfp;
460       if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break;
461
462     __array[i++] = (void*)(rfp[1]-4);
463   }
464   return i;
465 }
466
467 int
468 _Jv_pipe (int filedes[2])
469 {
470   return _pipe (filedes, 4096, _O_BINARY);
471 }
472
473 void
474 _Jv_platform_close_on_exec (HANDLE h)
475 {
476   // Mark the handle as non-inheritable. This has
477   // no effect under Win9X.
478   SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
479 }