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