]>
Commit | Line | Data |
---|---|---|
b8fe3c1e AM |
1 | // win32.cc - Helper functions for Microsoft-flavored OSs. |
2 | ||
a191802c | 3 | /* Copyright (C) 2002, 2003 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; | |
259 | if (WSAStartup (MAKEWORD (1, 1), &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 | ||
9268f1c0 AM |
282 | // The following definitions "fake out" mingw to think that -mthreads |
283 | // was enabled and that mingwthr.dll was linked. GCJ-compiled | |
284 | // applications don't need this helper library because we can safely | |
285 | // detect thread death (return from Thread.run()). | |
286 | ||
287 | int _CRT_MT = 1; | |
288 | ||
289 | extern "C" int | |
290 | __mingwthr_key_dtor (DWORD, void (*) (void *)) | |
291 | { | |
292 | // FIXME: for now we do nothing; this causes a memory leak of | |
293 | // approximately 24 bytes per thread created. | |
294 | return 0; | |
295 | } | |
455cd615 | 296 | |
83c02e38 | 297 | static bool dirExists (LPCTSTR dir) |
748e241e ME |
298 | { |
299 | DWORD dwAttrs = ::GetFileAttributes (dir); | |
300 | return dwAttrs != 0xFFFFFFFF && | |
301 | (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
302 | } | |
303 | ||
83c02e38 | 304 | static void getUserHome(LPTSTR userHome, LPCTSTR userId) |
748e241e | 305 | { |
83c02e38 | 306 | LPTSTR uh = _tgetenv (_T("USERPROFILE")); |
748e241e ME |
307 | if (uh) |
308 | { | |
83c02e38 | 309 | _tcscpy(userHome, uh); |
748e241e ME |
310 | } |
311 | else | |
312 | { | |
313 | // Make a half-hearted attempt to support this | |
314 | // legacy version of Windows. Try %WINDIR%\Profiles\%USERNAME% | |
315 | // and failing this, use %WINDIR%. | |
316 | // | |
317 | // See:http://java.sun.com/docs/books/tutorial/security1.2/summary/files.html#UserPolicy | |
318 | // | |
319 | // To do this correctly, we'd have to factor in the | |
320 | // Windows version, but if we did that, then this attempt | |
321 | // wouldn't be half-hearted. | |
83c02e38 | 322 | TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH]; |
748e241e ME |
323 | ::GetWindowsDirectory(winHome, MAX_PATH); |
324 | // assume this call always succeeds | |
325 | ||
83c02e38 | 326 | _stprintf(userHomePath, _T("%s\\Profiles\\%s"), winHome, userId); |
748e241e | 327 | if (dirExists (userHomePath)) |
83c02e38 | 328 | _tcscpy(userHome, userHomePath); |
748e241e | 329 | else |
83c02e38 | 330 | _tcscpy(userHome, winHome); |
748e241e ME |
331 | } |
332 | } | |
333 | ||
455cd615 AK |
334 | // Set platform-specific System properties. |
335 | void | |
336 | _Jv_platform_initProperties (java::util::Properties* newprops) | |
337 | { | |
338 | // A convenience define. | |
339 | #define SET(Prop,Val) \ | |
83c02e38 | 340 | newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val)) |
455cd615 | 341 | |
83c02e38 ME |
342 | SET ("file.separator", _T("\\")); |
343 | SET ("path.separator", _T(";")); | |
344 | SET ("line.separator", _T("\r\n")); | |
455cd615 AK |
345 | |
346 | // Use GetCurrentDirectory to set 'user.dir'. | |
347 | DWORD buflen = MAX_PATH; | |
83c02e38 | 348 | TCHAR buffer[buflen]; |
455cd615 AK |
349 | if (buffer != NULL) |
350 | { | |
351 | if (GetCurrentDirectory (buflen, buffer)) | |
5c144158 | 352 | SET ("user.dir", buffer); |
94ed0002 AK |
353 | |
354 | if (GetTempPath (buflen, buffer)) | |
5c144158 | 355 | SET ("java.io.tmpdir", buffer); |
455cd615 | 356 | } |
5c144158 | 357 | |
455cd615 AK |
358 | // Use GetUserName to set 'user.name'. |
359 | buflen = 257; // UNLEN + 1 | |
83c02e38 | 360 | TCHAR userName[buflen]; |
748e241e ME |
361 | if (GetUserName (userName, &buflen)) |
362 | SET ("user.name", userName); | |
363 | ||
364 | // Set user.home | |
83c02e38 | 365 | TCHAR userHome[MAX_PATH]; |
748e241e ME |
366 | getUserHome(userHome, userName); |
367 | SET ("user.home", userHome); | |
455cd615 AK |
368 | |
369 | // Get and set some OS info. | |
370 | OSVERSIONINFO osvi; | |
371 | ZeroMemory (&osvi, sizeof(OSVERSIONINFO)); | |
372 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
373 | if (GetVersionEx (&osvi)) | |
374 | { | |
455cd615 AK |
375 | if (buffer != NULL) |
376 | { | |
83c02e38 | 377 | _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion, |
5c144158 | 378 | (int) osvi.dwMinorVersion); |
455cd615 | 379 | SET ("os.version", buffer); |
455cd615 AK |
380 | } |
381 | ||
382 | switch (osvi.dwPlatformId) | |
383 | { | |
384 | case VER_PLATFORM_WIN32_WINDOWS: | |
385 | if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) | |
83c02e38 | 386 | SET ("os.name", _T("Windows 95")); |
455cd615 | 387 | else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) |
83c02e38 | 388 | SET ("os.name", _T("Windows 98")); |
455cd615 | 389 | else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) |
83c02e38 | 390 | SET ("os.name", _T("Windows Me")); |
455cd615 | 391 | else |
83c02e38 | 392 | SET ("os.name", _T("Windows ??")); |
455cd615 AK |
393 | break; |
394 | ||
395 | case VER_PLATFORM_WIN32_NT: | |
396 | if (osvi.dwMajorVersion <= 4 ) | |
83c02e38 | 397 | SET ("os.name", _T("Windows NT")); |
455cd615 | 398 | else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) |
83c02e38 | 399 | SET ("os.name", _T("Windows 2000")); |
455cd615 | 400 | else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) |
83c02e38 | 401 | SET ("os.name", _T("Windows XP")); |
455cd615 | 402 | else |
83c02e38 | 403 | SET ("os.name", _T("Windows NT ??")); |
455cd615 AK |
404 | break; |
405 | ||
406 | default: | |
83c02e38 | 407 | SET ("os.name", _T("Windows UNKNOWN")); |
455cd615 AK |
408 | break; |
409 | } | |
410 | } | |
411 | ||
412 | // Set the OS architecture. | |
413 | SYSTEM_INFO si; | |
414 | GetSystemInfo (&si); | |
14a5a676 | 415 | switch (si.wProcessorArchitecture) |
455cd615 | 416 | { |
14a5a676 | 417 | case PROCESSOR_ARCHITECTURE_INTEL: |
83c02e38 | 418 | SET ("os.arch", _T("x86")); |
455cd615 | 419 | break; |
14a5a676 | 420 | case PROCESSOR_ARCHITECTURE_MIPS: |
83c02e38 | 421 | SET ("os.arch", _T("mips")); |
455cd615 | 422 | break; |
14a5a676 | 423 | case PROCESSOR_ARCHITECTURE_ALPHA: |
83c02e38 | 424 | SET ("os.arch", _T("alpha")); |
455cd615 | 425 | break; |
83c02e38 ME |
426 | case PROCESSOR_ARCHITECTURE_PPC: |
427 | SET ("os.arch", _T("ppc")); | |
455cd615 | 428 | break; |
14a5a676 | 429 | case PROCESSOR_ARCHITECTURE_IA64: |
83c02e38 | 430 | SET ("os.arch", _T("ia64")); |
455cd615 | 431 | break; |
14a5a676 | 432 | case PROCESSOR_ARCHITECTURE_UNKNOWN: |
455cd615 | 433 | default: |
83c02e38 | 434 | SET ("os.arch", _T("unknown")); |
455cd615 AK |
435 | break; |
436 | } | |
437 | } | |
c2a6704f AM |
438 | |
439 | /* Store up to SIZE return address of the current program state in | |
440 | ARRAY and return the exact number of values stored. */ | |
441 | int | |
442 | backtrace (void **__array, int __size) | |
443 | { | |
444 | register void *_ebp __asm__ ("ebp"); | |
445 | register void *_esp __asm__ ("esp"); | |
446 | unsigned int *rfp; | |
447 | ||
448 | int i=0; | |
449 | for (rfp = *(unsigned int**)_ebp; | |
450 | rfp && i < __size; | |
451 | rfp = *(unsigned int **)rfp) | |
452 | { | |
453 | int diff = *rfp - (unsigned int)rfp; | |
454 | if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break; | |
455 | ||
456 | __array[i++] = (void*)(rfp[1]-4); | |
457 | } | |
458 | return i; | |
459 | } | |
5c144158 | 460 | |
ef050c9e ME |
461 | int |
462 | _Jv_pipe (int filedes[2]) | |
463 | { | |
464 | return _pipe (filedes, 4096, _O_BINARY); | |
465 | } | |
bbf76ec0 ME |
466 | |
467 | void | |
468 | _Jv_platform_close_on_exec (HANDLE h) | |
469 | { | |
470 | // Mark the handle as non-inheritable. This has | |
471 | // no effect under Win9X. | |
472 | SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0); | |
473 | } |