]>
Commit | Line | Data |
---|---|---|
b8fe3c1e AM |
1 | // win32.cc - Helper functions for Microsoft-flavored OSs. |
2 | ||
e59a1e40 | 3 | /* Copyright (C) 2002, 2003, 2006 Free Software Foundation |
b8fe3c1e AM |
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> | |
a191802c | 12 | #include <platform.h> |
8eeda6e0 | 13 | #include <sys/timeb.h> |
455cd615 | 14 | #include <stdlib.h> |
ef050c9e | 15 | #include <fcntl.h> |
b8fe3c1e | 16 | |
1febeb40 | 17 | #include <java/lang/ArithmeticException.h> |
5c144158 ME |
18 | #include <java/lang/UnsupportedOperationException.h> |
19 | #include <java/io/IOException.h> | |
20 | #include <java/net/SocketException.h> | |
455cd615 | 21 | #include <java/util/Properties.h> |
73272ce6 TT |
22 | |
23 | static LONG CALLBACK | |
b8fe3c1e AM |
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 | } | |
73272ce6 | 33 | |
c068c638 AH |
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 | ||
5c144158 ME |
43 | // Helper classes and methods implementation |
44 | ||
83c02e38 ME |
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 | ||
5c144158 | 145 | // class WSAEventWrapper |
5cd4d463 ME |
146 | WSAEventWrapper::WSAEventWrapper (): |
147 | m_hEvent(0), | |
148 | m_fd(0), | |
149 | m_dwSelFlags(0) | |
150 | {} | |
151 | ||
5c144158 ME |
152 | WSAEventWrapper::WSAEventWrapper (int fd, DWORD dwSelFlags): |
153 | m_hEvent(0), | |
5cd4d463 ME |
154 | m_fd(0), |
155 | m_dwSelFlags(0) | |
156 | { | |
157 | init(fd, dwSelFlags); | |
158 | } | |
159 | ||
160 | void WSAEventWrapper::init(int fd, DWORD dwSelFlags) | |
5c144158 | 161 | { |
5cd4d463 ME |
162 | m_fd = fd; |
163 | m_dwSelFlags = dwSelFlags; | |
5c144158 ME |
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 = | |
83c02e38 ME |
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); | |
5c144158 ME |
215 | } |
216 | else | |
217 | { | |
83c02e38 | 218 | ret = _Jv_Win32NewString (lpMsgBuf); |
5c144158 ME |
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 | ||
73272ce6 TT |
253 | // Platform-specific VM initialization. |
254 | void | |
255 | _Jv_platform_initialize (void) | |
256 | { | |
257 | // Initialise winsock for networking | |
258 | WSADATA data; | |
5b5662ee | 259 | if (WSAStartup (MAKEWORD (2, 2), &data)) |
83c02e38 | 260 | MessageBox (NULL, _T("Error initialising winsock library."), _T("Error"), |
5c144158 ME |
261 | MB_OK | MB_ICONEXCLAMATION); |
262 | ||
73272ce6 TT |
263 | // Install exception handler |
264 | SetUnhandledExceptionFilter (win32_exception_handler); | |
5c144158 | 265 | |
83c02e38 ME |
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)); | |
73272ce6 | 271 | } |
b32d2321 AM |
272 | |
273 | // gettimeofday implementation. | |
8eeda6e0 AM |
274 | jlong |
275 | _Jv_platform_gettimeofday () | |
b32d2321 | 276 | { |
8eeda6e0 AM |
277 | struct timeb t; |
278 | ftime (&t); | |
bb0774f3 | 279 | return t.time * 1000LL + t.millitm; |
b32d2321 AM |
280 | } |
281 | ||
e59a1e40 TT |
282 | jlong |
283 | _Jv_platform_nanotime () | |
284 | { | |
285 | return _Jv_platform_gettimeofday () * 1000LL; | |
286 | } | |
287 | ||
9268f1c0 AM |
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 | } | |
455cd615 | 302 | |
83c02e38 | 303 | static bool dirExists (LPCTSTR dir) |
748e241e ME |
304 | { |
305 | DWORD dwAttrs = ::GetFileAttributes (dir); | |
306 | return dwAttrs != 0xFFFFFFFF && | |
307 | (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
308 | } | |
309 | ||
83c02e38 | 310 | static void getUserHome(LPTSTR userHome, LPCTSTR userId) |
748e241e | 311 | { |
83c02e38 | 312 | LPTSTR uh = _tgetenv (_T("USERPROFILE")); |
748e241e ME |
313 | if (uh) |
314 | { | |
83c02e38 | 315 | _tcscpy(userHome, uh); |
748e241e ME |
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. | |
83c02e38 | 328 | TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH]; |
748e241e ME |
329 | ::GetWindowsDirectory(winHome, MAX_PATH); |
330 | // assume this call always succeeds | |
331 | ||
83c02e38 | 332 | _stprintf(userHomePath, _T("%s\\Profiles\\%s"), winHome, userId); |
748e241e | 333 | if (dirExists (userHomePath)) |
83c02e38 | 334 | _tcscpy(userHome, userHomePath); |
748e241e | 335 | else |
83c02e38 | 336 | _tcscpy(userHome, winHome); |
748e241e ME |
337 | } |
338 | } | |
339 | ||
455cd615 AK |
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) \ | |
83c02e38 | 346 | newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val)) |
455cd615 | 347 | |
83c02e38 ME |
348 | SET ("file.separator", _T("\\")); |
349 | SET ("path.separator", _T(";")); | |
350 | SET ("line.separator", _T("\r\n")); | |
455cd615 AK |
351 | |
352 | // Use GetCurrentDirectory to set 'user.dir'. | |
353 | DWORD buflen = MAX_PATH; | |
83c02e38 | 354 | TCHAR buffer[buflen]; |
455cd615 AK |
355 | if (buffer != NULL) |
356 | { | |
357 | if (GetCurrentDirectory (buflen, buffer)) | |
5c144158 | 358 | SET ("user.dir", buffer); |
94ed0002 AK |
359 | |
360 | if (GetTempPath (buflen, buffer)) | |
5c144158 | 361 | SET ("java.io.tmpdir", buffer); |
455cd615 | 362 | } |
5c144158 | 363 | |
455cd615 AK |
364 | // Use GetUserName to set 'user.name'. |
365 | buflen = 257; // UNLEN + 1 | |
83c02e38 | 366 | TCHAR userName[buflen]; |
748e241e ME |
367 | if (GetUserName (userName, &buflen)) |
368 | SET ("user.name", userName); | |
369 | ||
370 | // Set user.home | |
83c02e38 | 371 | TCHAR userHome[MAX_PATH]; |
748e241e ME |
372 | getUserHome(userHome, userName); |
373 | SET ("user.home", userHome); | |
455cd615 AK |
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 | { | |
455cd615 AK |
381 | if (buffer != NULL) |
382 | { | |
83c02e38 | 383 | _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion, |
5c144158 | 384 | (int) osvi.dwMinorVersion); |
455cd615 | 385 | SET ("os.version", buffer); |
455cd615 AK |
386 | } |
387 | ||
388 | switch (osvi.dwPlatformId) | |
389 | { | |
390 | case VER_PLATFORM_WIN32_WINDOWS: | |
391 | if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) | |
83c02e38 | 392 | SET ("os.name", _T("Windows 95")); |
455cd615 | 393 | else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) |
83c02e38 | 394 | SET ("os.name", _T("Windows 98")); |
455cd615 | 395 | else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) |
83c02e38 | 396 | SET ("os.name", _T("Windows Me")); |
455cd615 | 397 | else |
83c02e38 | 398 | SET ("os.name", _T("Windows ??")); |
455cd615 AK |
399 | break; |
400 | ||
401 | case VER_PLATFORM_WIN32_NT: | |
402 | if (osvi.dwMajorVersion <= 4 ) | |
83c02e38 | 403 | SET ("os.name", _T("Windows NT")); |
455cd615 | 404 | else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) |
83c02e38 | 405 | SET ("os.name", _T("Windows 2000")); |
455cd615 | 406 | else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) |
83c02e38 | 407 | SET ("os.name", _T("Windows XP")); |
455cd615 | 408 | else |
83c02e38 | 409 | SET ("os.name", _T("Windows NT ??")); |
455cd615 AK |
410 | break; |
411 | ||
412 | default: | |
83c02e38 | 413 | SET ("os.name", _T("Windows UNKNOWN")); |
455cd615 AK |
414 | break; |
415 | } | |
416 | } | |
417 | ||
418 | // Set the OS architecture. | |
419 | SYSTEM_INFO si; | |
420 | GetSystemInfo (&si); | |
14a5a676 | 421 | switch (si.wProcessorArchitecture) |
455cd615 | 422 | { |
14a5a676 | 423 | case PROCESSOR_ARCHITECTURE_INTEL: |
83c02e38 | 424 | SET ("os.arch", _T("x86")); |
455cd615 | 425 | break; |
14a5a676 | 426 | case PROCESSOR_ARCHITECTURE_MIPS: |
83c02e38 | 427 | SET ("os.arch", _T("mips")); |
455cd615 | 428 | break; |
14a5a676 | 429 | case PROCESSOR_ARCHITECTURE_ALPHA: |
83c02e38 | 430 | SET ("os.arch", _T("alpha")); |
455cd615 | 431 | break; |
83c02e38 ME |
432 | case PROCESSOR_ARCHITECTURE_PPC: |
433 | SET ("os.arch", _T("ppc")); | |
455cd615 | 434 | break; |
14a5a676 | 435 | case PROCESSOR_ARCHITECTURE_IA64: |
83c02e38 | 436 | SET ("os.arch", _T("ia64")); |
455cd615 | 437 | break; |
14a5a676 | 438 | case PROCESSOR_ARCHITECTURE_UNKNOWN: |
455cd615 | 439 | default: |
83c02e38 | 440 | SET ("os.arch", _T("unknown")); |
455cd615 AK |
441 | break; |
442 | } | |
443 | } | |
c2a6704f AM |
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 | } | |
5c144158 | 466 | |
ef050c9e ME |
467 | int |
468 | _Jv_pipe (int filedes[2]) | |
469 | { | |
470 | return _pipe (filedes, 4096, _O_BINARY); | |
471 | } | |
bbf76ec0 ME |
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 | } |