diff options
author | rubidium <rubidium@openttd.org> | 2007-01-02 19:19:48 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2007-01-02 19:19:48 +0000 |
commit | 013df98f79866a75f367853c9e436f3c5c79f645 (patch) | |
tree | ad4a63860df2626b22f77e7dac712e958bea54cb /win32.c | |
parent | 3d32fd3f4bfaceb8a48530fbc2f4bd5db2752596 (diff) | |
download | openttd-013df98f79866a75f367853c9e436f3c5c79f645.tar.xz |
(svn r7759) -Merge: makefile rewrite. This merge features:
- A proper ./configure, so everything needs to be configured only once, not for every make.
- Usage of makedepend when available. This greatly reduces the time needed for generating the dependencies.
- A generator for all project files. There is a single file with sources, which is used to generate Makefiles and the project files for MSVC.
- Proper support for OSX universal binaries.
- Object files for non-MSVC compiles are also placed in separate directories, making is faster to switch between debug and release compiles and it does not touch the directory with the source files.
- Functionality to make a bundle of all needed files for for example a nightly or distribution of a binary with all needed GRFs and language files.
Note: as this merge moves almost all files, it is recommended to make a backup of your working copy before updating your working copy.
Diffstat (limited to 'win32.c')
-rw-r--r-- | win32.c | 1140 |
1 files changed, 0 insertions, 1140 deletions
diff --git a/win32.c b/win32.c deleted file mode 100644 index a0a3d05b4..000000000 --- a/win32.c +++ /dev/null @@ -1,1140 +0,0 @@ -/* $Id$ */ - -#include "stdafx.h" -#include "openttd.h" -#include "debug.h" -#include "functions.h" -#include "macros.h" -#include "saveload.h" -#include "string.h" -#include "gfx.h" -#include "window.h" -#include <windows.h> -#include <winnt.h> -#include <wininet.h> -#include <io.h> -#include <fcntl.h> -#include <shlobj.h> // SHGetFolderPath -#include "variables.h" -#include "win32.h" -#include "fios.h" // opendir/readdir/closedir -#include <ctype.h> -#include <tchar.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> - -static bool _has_console; - -#if defined(__MINGW32__) - #include <stdint.h> -#endif - -static bool cursor_visible = true; - -bool MyShowCursor(bool show) -{ - if (cursor_visible == show) return show; - - cursor_visible = show; - ShowCursor(show); - - return !show; -} - -/** Helper function needed by dynamically loading libraries - * XXX: Hurray for MS only having an ANSI GetProcAddress function - * on normal windows and no Wide version except for in Windows Mobile/CE */ -bool LoadLibraryList(Function proc[], const char *dll) -{ - while (*dll != '\0') { - HMODULE lib; - lib = LoadLibrary(MB_TO_WIDE(dll)); - - if (lib == NULL) return false; - for (;;) { - FARPROC p; - - while (*dll++ != '\0'); - if (*dll == '\0') break; -#if defined(WINCE) - p = GetProcAddress(lib, MB_TO_WIDE(dll); -#else - p = GetProcAddress(lib, dll); -#endif - if (p == NULL) return false; - *proc++ = (Function)p; - } - dll++; - } - return true; -} - -#ifdef _MSC_VER -static const char *_exception_string = NULL; -#endif - -void ShowOSErrorBox(const char *buf) -{ - MyShowCursor(true); - MessageBox(GetActiveWindow(), MB_TO_WIDE(buf), _T("Error!"), MB_ICONSTOP); - -// if exception tracker is enabled, we crash here to let the exception handler handle it. -#if defined(WIN32_EXCEPTION_TRACKER) && !defined(_DEBUG) - if (*buf == '!') { - _exception_string = buf; - *(byte*)0 = 0; - } -#endif -} - -#ifdef _MSC_VER - -static void *_safe_esp; -static char *_crash_msg; -static bool _expanded; -static bool _did_emerg_save; -static int _ident; - -typedef struct DebugFileInfo { - uint32 size; - uint32 crc32; - SYSTEMTIME file_time; -} DebugFileInfo; - -static uint32 *_crc_table; - -static void MakeCRCTable(uint32 *table) { - uint32 crc, poly = 0xEDB88320L; - int i; - int j; - - _crc_table = table; - - for (i = 0; i != 256; i++) { - crc = i; - for (j = 8; j != 0; j--) { - crc = (crc & 1 ? (crc >> 1) ^ poly : crc >> 1); - } - table[i] = crc; - } -} - -static uint32 CalcCRC(byte *data, uint size, uint32 crc) { - for (; size > 0; size--) { - crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF]; - } - return crc; -} - -static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename) -{ - HANDLE file; - memset(dfi, 0, sizeof(dfi)); - - file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - if (file != INVALID_HANDLE_VALUE) { - byte buffer[1024]; - DWORD numread; - uint32 filesize = 0; - FILETIME write_time; - uint32 crc = (uint32)-1; - - for (;;) { - if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 || numread == 0) - break; - filesize += numread; - crc = CalcCRC(buffer, numread, crc); - } - dfi->size = filesize; - dfi->crc32 = crc ^ (uint32)-1; - - if (GetFileTime(file, NULL, NULL, &write_time)) { - FileTimeToSystemTime(&write_time, &dfi->file_time); - } - CloseHandle(file); - } -} - - -static char *PrintModuleInfo(char *output, HMODULE mod) -{ - TCHAR buffer[MAX_PATH]; - DebugFileInfo dfi; - - GetModuleFileName(mod, buffer, MAX_PATH); - GetFileInfo(&dfi, buffer); - output += sprintf(output, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n", - WIDE_TO_MB(buffer), - mod, - dfi.size, - dfi.crc32, - dfi.file_time.wYear, - dfi.file_time.wMonth, - dfi.file_time.wDay, - dfi.file_time.wHour, - dfi.file_time.wMinute, - dfi.file_time.wSecond - ); - return output; -} - -static char *PrintModuleList(char *output) -{ - BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD); - - if (LoadLibraryList((Function*)&EnumProcessModules, "psapi.dll\0EnumProcessModules\0\0")) { - HMODULE modules[100]; - DWORD needed; - BOOL res; - int count, i; - - HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); - if (proc != NULL) { - res = EnumProcessModules(proc, modules, sizeof(modules), &needed); - CloseHandle(proc); - if (res) { - count = min(needed / sizeof(HMODULE), lengthof(modules)); - - for (i = 0; i != count; i++) output = PrintModuleInfo(output, modules[i]); - return output; - } - } - } - output = PrintModuleInfo(output, NULL); - return output; -} - -static const TCHAR _crash_desc[] = - _T("A serious fault condition occured in the game. The game will shut down.\n") - _T("Press \"Submit report\" to send crash information to the developers. ") - _T("This will greatly help debugging. ") - _T("The information contained in the report is displayed below.\n") - _T("Press \"Emergency save\" to attempt saving the game."); - -static const TCHAR _save_succeeded[] = - _T("Emergency save succeeded.\n") - _T("Be aware that critical parts of the internal game state may have become ") - _T("corrupted. The saved game is not guaranteed to work."); - -static bool EmergencySave(void) -{ - SaveOrLoad("crash.sav", SL_SAVE); - return true; -} - -/* Disable the crash-save submit code as it's not used */ -#if 0 - -typedef struct { - HINTERNET (WINAPI *InternetOpen)(LPCTSTR,DWORD, LPCTSTR, LPCTSTR, DWORD); - HINTERNET (WINAPI *InternetConnect)(HINTERNET, LPCTSTR, INTERNET_PORT, LPCTSTR, LPCTSTR, DWORD, DWORD, DWORD); - HINTERNET (WINAPI *HttpOpenRequest)(HINTERNET, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR *, DWORD, DWORD); - BOOL (WINAPI *HttpSendRequest)(HINTERNET, LPCTSTR, DWORD, LPVOID, DWORD); - BOOL (WINAPI *InternetCloseHandle)(HINTERNET); - BOOL (WINAPI *HttpQueryInfo)(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD); -} WinInetProcs; - -#define M(x) x "\0" -#if defined(UNICODE) -# define W(x) x "W" -#else -# define W(x) x "A" -#endif -static const char wininet_files[] = - M("wininet.dll") - M(W("InternetOpen")) - M(W("InternetConnect")) - M(W("HttpOpenRequest")) - M(W("HttpSendRequest")) - M("InternetCloseHandle") - M(W("HttpQueryInfo")) - M(""); -#undef W -#undef M - -static WinInetProcs _wininet; - -static const TCHAR *SubmitCrashReport(HWND wnd, void *msg, size_t msglen, const TCHAR *arg) -{ - HINTERNET inet, conn, http; - const TCHAR *err = NULL; - DWORD code, len; - static TCHAR buf[100]; - TCHAR buff[100]; - - if (_wininet.InternetOpen == NULL && !LoadLibraryList((Function*)&_wininet, wininet_files)) return _T("can't load wininet.dll"); - - inet = _wininet.InternetOpen(_T("OTTD"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ); - if (inet == NULL) { err = _T("internetopen failed"); goto error1; } - - conn = _wininet.InternetConnect(inet, _T("www.openttd.org"), INTERNET_DEFAULT_HTTP_PORT, _T(""), _T(""), INTERNET_SERVICE_HTTP, 0, 0); - if (conn == NULL) { err = _T("internetconnect failed"); goto error2; } - - _sntprintf(buff, lengthof(buff), _T("/crash.php?file=%s&ident=%d"), arg, _ident); - - http = _wininet.HttpOpenRequest(conn, _T("POST"), buff, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE , 0); - if (http == NULL) { err = _T("httpopenrequest failed"); goto error3; } - - if (!_wininet.HttpSendRequest(http, _T("Content-type: application/binary"), -1, msg, (DWORD)msglen)) { err = _T("httpsendrequest failed"); goto error4; } - - len = sizeof(code); - if (!_wininet.HttpQueryInfo(http, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &code, &len, 0)) { err = _T("httpqueryinfo failed"); goto error4; } - - if (code != 200) { - int l = _sntprintf(buf, lengthof(buf), _T("Server said: %d "), code); - len = sizeof(buf) - l; - _wininet.HttpQueryInfo(http, HTTP_QUERY_STATUS_TEXT, buf + l, &len, 0); - err = buf; - } - -error4: - _wininet.InternetCloseHandle(http); -error3: - _wininet.InternetCloseHandle(conn); -error2: - _wininet.InternetCloseHandle(inet); -error1: - return err; -} - -static void SubmitFile(HWND wnd, const TCHAR *file) -{ - HANDLE h; - unsigned long size; - unsigned long read; - void *mem; - - h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (h == NULL) return; - - size = GetFileSize(h, NULL); - if (size > 500000) goto error1; - - mem = malloc(size); - if (mem == NULL) goto error1; - - if (!ReadFile(h, mem, size, &read, NULL) || read != size) goto error2; - - SubmitCrashReport(wnd, mem, size, file); - -error2: - free(mem); -error1: - CloseHandle(h); -} - -#endif /* Disabled crash-submit procedures */ - -static const TCHAR * const _expand_texts[] = {_T("S&how report >>"), _T("&Hide report <<") }; - -static void SetWndSize(HWND wnd, int mode) -{ - RECT r,r2; - int offs; - - GetWindowRect(wnd, &r); - - SetDlgItemText(wnd, 15, _expand_texts[mode == 1]); - - if (mode >= 0) { - GetWindowRect(GetDlgItem(wnd, 11), &r2); - offs = r2.bottom - r2.top + 10; - if (!mode) offs = -offs; - SetWindowPos(wnd, HWND_TOPMOST, 0, 0, - r.right - r.left, r.bottom - r.top + offs, SWP_NOMOVE | SWP_NOZORDER); - } else { - SetWindowPos(wnd, HWND_TOPMOST, - (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2, - (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2, - 0, 0, SWP_NOSIZE); - } -} - -static bool DoEmergencySave(HWND wnd) -{ - bool b = false; - - EnableWindow(GetDlgItem(wnd, 13), FALSE); - _did_emerg_save = true; - __try { - b = EmergencySave(); - } __except (1) {} - return b; -} - -static INT_PTR CALLBACK CrashDialogFunc(HWND wnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: { -#if defined(UNICODE) - /* We need to put the crash-log in a seperate buffer because the default - * buffer in MB_TO_WIDE is not large enough (256 chars) */ - wchar_t crash_msgW[8096]; -#endif - SetDlgItemText(wnd, 10, _crash_desc); - SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(_crash_msg, crash_msgW, lengthof(crash_msgW))); - SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE); - SetWndSize(wnd, -1); - } return TRUE; - case WM_COMMAND: - switch (wParam) { - case 12: /* Close */ - ExitProcess(0); - case 13: /* Emergency save */ - if (DoEmergencySave(wnd)) { - MessageBox(wnd, _save_succeeded, _T("Save successful"), MB_ICONINFORMATION); - } else { - MessageBox(wnd, _T("Save failed"), _T("Save failed"), MB_ICONINFORMATION); - } - break; -/* Disable the crash-save submit code as it's not used */ -#if 0 - case 14: { /* Submit crash report */ - const TCHAR *s; - - SetCursor(LoadCursor(NULL, IDC_WAIT)); - - s = SubmitCrashReport(wnd, _crash_msg, strlen(_crash_msg), _T("")); - if (s != NULL) { - MessageBox(wnd, s, _T("Error"), MB_ICONSTOP); - break; - } - - // try to submit emergency savegame - if (_did_emerg_save || DoEmergencySave(wnd)) SubmitFile(wnd, _T("crash.sav")); - - // try to submit the autosaved game - if (_opt.autosave) { - TCHAR buf[40]; - _sntprintf(buf, lengthof(buf), _T("autosave%d.sav"), (_autosave_ctr - 1) & 3); - SubmitFile(wnd, buf); - } - EnableWindow(GetDlgItem(wnd, 14), FALSE); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - MessageBox(wnd, _T("Crash report submitted. Thank you."), _T("Crash Report"), MB_ICONINFORMATION); - } break; -#endif /* Disabled crash-submit procedures */ - case 15: /* Expand window to show crash-message */ - _expanded ^= 1; - SetWndSize(wnd, _expanded); - break; - } - return TRUE; - case WM_CLOSE: ExitProcess(0); - } - - return FALSE; -} - -static void Handler2(void) -{ - ShowCursor(TRUE); - ShowWindow(GetActiveWindow(), FALSE); - DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(100), NULL, CrashDialogFunc); -} - -extern bool CloseConsoleLogIfActive(void); - -static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) -{ - extern const char _openttd_revision[]; - char *output; - static bool had_exception = false; - - if (had_exception) ExitProcess(0); - had_exception = true; - - _ident = GetTickCount(); // something pretty unique - - MakeCRCTable(alloca(256 * sizeof(uint32))); - _crash_msg = output = LocalAlloc(LMEM_FIXED, 8192); - - { - SYSTEMTIME time; - GetLocalTime(&time); - output += sprintf(output, - "*** OpenTTD Crash Report ***\r\n" - "Date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n" - "Build: %s built on " __DATE__ " " __TIME__ "\r\n", - time.wYear, - time.wMonth, - time.wDay, - time.wHour, - time.wMinute, - time.wSecond, - _openttd_revision - ); - } - - if (_exception_string) - output += sprintf(output, "Reason: %s\r\n", _exception_string); - -#ifdef _M_AMD64 - output += sprintf(output, "Exception %.8X at %.16IX\r\n" - "Registers:\r\n" - "RAX: %.16llX RBX: %.16llX RCX: %.16llX RDX: %.16llX\r\n" - "RSI: %.16llX RDI: %.16llX RBP: %.16llX RSP: %.16llX\r\n" - "R8: %.16llX R9: %.16llX R10: %.16llX R11: %.16llX\r\n" - "R12: %.16llX R13: %.16llX R14: %.16llX R15: %.16llX\r\n" - "RIP: %.16llX EFLAGS: %.8X\r\n" - "\r\nBytes at CS:RIP:\r\n", - ep->ExceptionRecord->ExceptionCode, - ep->ExceptionRecord->ExceptionAddress, - ep->ContextRecord->Rax, - ep->ContextRecord->Rbx, - ep->ContextRecord->Rcx, - ep->ContextRecord->Rdx, - ep->ContextRecord->Rsi, - ep->ContextRecord->Rdi, - ep->ContextRecord->Rbp, - ep->ContextRecord->Rsp, - ep->ContextRecord->R8, - ep->ContextRecord->R9, - ep->ContextRecord->R10, - ep->ContextRecord->R11, - ep->ContextRecord->R12, - ep->ContextRecord->R13, - ep->ContextRecord->R14, - ep->ContextRecord->R15, - ep->ContextRecord->Rip, - ep->ContextRecord->EFlags - ); -#else - output += sprintf(output, "Exception %.8X at %.8X\r\n" - "Registers:\r\n" - " EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\r\n" - " ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\r\n" - " EIP: %.8X EFLAGS: %.8X\r\n" - "\r\nBytes at CS:EIP:\r\n", - ep->ExceptionRecord->ExceptionCode, - ep->ExceptionRecord->ExceptionAddress, - ep->ContextRecord->Eax, - ep->ContextRecord->Ebx, - ep->ContextRecord->Ecx, - ep->ContextRecord->Edx, - ep->ContextRecord->Esi, - ep->ContextRecord->Edi, - ep->ContextRecord->Ebp, - ep->ContextRecord->Esp, - ep->ContextRecord->Eip, - ep->ContextRecord->EFlags - ); -#endif - - { -#ifdef _M_AMD64 - byte *b = (byte*)ep->ContextRecord->Rip; -#else - byte *b = (byte*)ep->ContextRecord->Eip; -#endif - int i; - for (i = 0; i != 24; i++) { - if (IsBadReadPtr(b, 1)) { - output += sprintf(output, " ??"); // OCR: WAS: , 0); - } else { - output += sprintf(output, " %.2X", *b); - } - b++; - } - output += sprintf(output, - "\r\n" - "\r\nStack trace: \r\n" - ); - } - - { - int i,j; -#ifdef _M_AMD64 - uint32 *b = (uint32*)ep->ContextRecord->Rsp; -#else - uint32 *b = (uint32*)ep->ContextRecord->Esp; -#endif - for (j = 0; j != 24; j++) { - for (i = 0; i != 8; i++) { - if (IsBadReadPtr(b,sizeof(uint32))) { - output += sprintf(output, " ????????"); //OCR: WAS - , 0); - } else { - output += sprintf(output, " %.8X", *b); - } - b++; - } - output += sprintf(output, "\r\n"); - } - } - - output += sprintf(output, "\r\nModule information:\r\n"); - output = PrintModuleList(output); - - { - OSVERSIONINFO os; - os.dwOSVersionInfoSize = sizeof(os); - GetVersionEx(&os); - output += sprintf(output, "\r\nSystem information:\r\n" - " Windows version %d.%d %d %s\r\n", - os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.szCSDVersion); - } - - { - HANDLE file = CreateFile(_T("crash.log"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); - DWORD num_written; - if (file != INVALID_HANDLE_VALUE) { - WriteFile(file, _crash_msg, output - _crash_msg, &num_written, NULL); - CloseHandle(file); - } - } - - /* Close any possible log files */ - CloseConsoleLogIfActive(); - - if (_safe_esp) { -#ifdef _M_AMD64 - ep->ContextRecord->Rip = (DWORD64)Handler2; - ep->ContextRecord->Rsp = (DWORD64)_safe_esp; -#else - ep->ContextRecord->Eip = (DWORD)Handler2; - ep->ContextRecord->Esp = (DWORD)_safe_esp; -#endif - return EXCEPTION_CONTINUE_EXECUTION; - } - - - return EXCEPTION_EXECUTE_HANDLER; -} - -static void Win32InitializeExceptions(void) -{ -#ifdef _M_AMD64 - extern void *_get_save_esp(void); - _safe_esp = _get_save_esp(); -#else - _asm { - mov _safe_esp, esp - } -#endif - - SetUnhandledExceptionFilter(ExceptionHandler); -} -#endif /* _MSC_VER */ - -/* Code below for windows version of opendir/readdir/closedir copied and - * modified from Jan Wassenberg's GPL implementation posted over at - * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1� */ - -/* suballocator - satisfies most requests with a reusable static instance. - * this avoids hundreds of alloc/free which would fragment the heap. - * To guarantee reentrancy, we fall back to malloc if the instance is - * already in use (it's important to avoid suprises since this is such a - * low-level routine). */ -static DIR _global_dir; -static bool _global_dir_is_in_use = false; - -static inline DIR *dir_calloc(void) -{ - DIR *d; - - if (_global_dir_is_in_use) { - d = calloc(1, sizeof(*d)); - } else { - _global_dir_is_in_use = true; - d = &_global_dir; - memset(d, 0, sizeof(*d)); - } - return d; -} - -static inline void dir_free(DIR *d) -{ - if (d == &_global_dir) { - _global_dir_is_in_use = false; - } else { - free(d); - } -} - -DIR *opendir(const char *path) -{ - DIR *d; - UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box - DWORD fa = GetFileAttributesW(OTTD2FS(path)); - - if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { - d = dir_calloc(); - if (d != NULL) { - char search_path[MAX_PATH]; - /* build search path for FindFirstFile */ - snprintf(search_path, lengthof(search_path), "%s" PATHSEP "*", path); - d->hFind = FindFirstFileW(OTTD2FS(search_path), &d->fd); - - if (d->hFind != INVALID_HANDLE_VALUE || - GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty - d->ent.dir = d; - d->at_first_entry = true; - } else { - dir_free(d); - d = NULL; - } - } else { - errno = ENOMEM; - } - } else { - /* path not found or not a directory */ - d = NULL; - errno = ENOENT; - } - - SetErrorMode(sem); // restore previous setting - return d; -} - -struct dirent *readdir(DIR *d) -{ - DWORD prev_err = GetLastError(); // avoid polluting last error - - if (d->at_first_entry) { - /* the directory was empty when opened */ - if (d->hFind == INVALID_HANDLE_VALUE) return NULL; - d->at_first_entry = false; - } else if (!FindNextFileW(d->hFind, &d->fd)) { // determine cause and bail - if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err); - return NULL; - } - - /* This entry has passed all checks; return information about it. - * (note: d_name is a pointer; see struct dirent definition) */ - d->ent.d_name = d->fd.cFileName; - return &d->ent; -} - -int closedir(DIR *d) -{ - FindClose(d->hFind); - dir_free(d); - return 0; -} - -bool FiosIsRoot(const char *file) -{ - return file[3] == '\0'; // C:\... -} - -void FiosGetDrives(void) -{ - TCHAR drives[256]; - const TCHAR *s; - - GetLogicalDriveStrings(sizeof(drives), drives); - for (s = drives; *s != '\0';) { - FiosItem *fios = FiosAlloc(); - fios->type = FIOS_TYPE_DRIVE; - fios->mtime = 0; - snprintf(fios->name, lengthof(fios->name), "%c:", s[0] & 0xFF); - ttd_strlcpy(fios->title, fios->name, lengthof(fios->title)); - while (*s++ != '\0'); - } -} - -bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb) -{ - // hectonanoseconds between Windows and POSIX epoch - static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL; - const WIN32_FIND_DATAW *fd = &ent->dir->fd; - if (fd->dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) return false; - - sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow; - /* UTC FILETIME to seconds-since-1970 UTC - * we just have to subtract POSIX epoch and scale down to units of seconds. - * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1� - * XXX - not entirely correct, since filetimes on FAT aren't UTC but local, - * this won't entirely be correct, but we use the time only for comparsion. */ - sb->st_mtime = (time_t)((*(uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7); - sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG; - - return true; -} - -bool FiosGetDiskFreeSpace(const char *path, uint32 *tot) -{ - UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box - bool retval = false; - TCHAR root[4]; - DWORD spc, bps, nfc, tnc; - - _sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]); - if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) { - *tot = ((spc * bps) * (uint64)nfc) >> 20; - retval = true; - } - - SetErrorMode(sem); // reset previous setting - return retval; -} - -static int ParseCommandLine(char *line, char **argv, int max_argc) -{ - int n = 0; - - do { - // skip whitespace - while (*line == ' ' || *line == '\t') line++; - - // end? - if (*line == '\0') break; - - // special handling when quoted - if (*line == '"') { - argv[n++] = ++line; - while (*line != '"') { - if (*line == '\0') return n; - line++; - } - } else { - argv[n++] = line; - while (*line != ' ' && *line != '\t') { - if (*line == '\0') return n; - line++; - } - } - *line++ = '\0'; - } while (n != max_argc); - - return n; -} - -void CreateConsole(void) -{ - HANDLE hand; - CONSOLE_SCREEN_BUFFER_INFO coninfo; - - if (_has_console) return; - _has_console = true; - - AllocConsole(); - - hand = GetStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(hand, &coninfo); - coninfo.dwSize.Y = 500; - SetConsoleScreenBufferSize(hand, coninfo.dwSize); - - // redirect unbuffered STDIN, STDOUT, STDERR to the console -#if !defined(__CYGWIN__) - *stdout = *_fdopen( _open_osfhandle((intptr_t)hand, _O_TEXT), "w" ); - *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" ); - *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" ); -#else - // open_osfhandle is not in cygwin - *stdout = *fdopen(1, "w" ); - *stdin = *fdopen(0, "r" ); - *stderr = *fdopen(2, "w" ); -#endif - - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); -} - -void ShowInfo(const char *str) -{ - if (_has_console) { - puts(str); - } else { - bool old; - - ReleaseCapture(); - _left_button_clicked =_left_button_down = false; - - old = MyShowCursor(true); - if (MessageBox(GetActiveWindow(), MB_TO_WIDE(str), _T("OpenTTD"), MB_ICONINFORMATION | MB_OKCANCEL) == IDCANCEL) { - CreateConsole(); - } - MyShowCursor(old); - } -} - -#ifdef __MINGW32__ - /* _set_error_mode() constants&function (do not exist in mingw headers) */ - #define _OUT_TO_DEFAULT 0 - #define _OUT_TO_STDERR 1 - #define _OUT_TO_MSGBOX 2 - #define _REPORT_ERRMODE 3 - int _set_error_mode(int); -#endif - -int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPTSTR lpCmdLine, int nCmdShow) -{ - int argc; - char *argv[64]; // max 64 command line arguments - char *cmdline; - -#if defined(UNICODE) - /* For UNICODE we need to convert the commandline to char* _AND_ - * save it because argv[] points into this buffer and thus needs to - * be available between subsequent calls to FS2OTTD() */ - char cmdlinebuf[MAX_PATH]; -#endif - - cmdline = WIDE_TO_MB_BUFFER(GetCommandLine(), cmdlinebuf, lengthof(cmdlinebuf)); - -#if defined(_DEBUG) - CreateConsole(); -#endif - - _set_error_mode(_OUT_TO_MSGBOX); // force assertion output to messagebox - - /* setup random seed to something quite random */ - _random_seeds[1][0] = _random_seeds[0][0] = GetTickCount(); - _random_seeds[1][1] = _random_seeds[0][1] = _random_seeds[0][0] * 0x1234567; - SeedMT(_random_seeds[0][0]); - - argc = ParseCommandLine(cmdline, argv, lengthof(argv)); - -#if defined(WIN32_EXCEPTION_TRACKER) - Win32InitializeExceptions(); -#endif - -#if defined(WIN32_EXCEPTION_TRACKER_DEBUG) - _try { - LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep); -#endif - ttd_main(argc, argv); - -#if defined(WIN32_EXCEPTION_TRACKER_DEBUG) - } _except (ExceptionHandler(_exception_info())) {} -#endif - - return 0; -} - -void DeterminePaths(void) -{ - char *s, *cfg; - wchar_t path[MAX_PATH]; - - _paths.personal_dir = _paths.game_data_dir = cfg = malloc(MAX_PATH); - GetCurrentDirectoryW(MAX_PATH - 1, path); - convert_from_fs(path, cfg, MAX_PATH); - - cfg[0] = toupper(cfg[0]); - s = strchr(cfg, '\0'); - if (s[-1] != '\\') strcpy(s, "\\"); - - _paths.save_dir = str_fmt("%ssave", cfg); - _paths.autosave_dir = str_fmt("%s\\autosave", _paths.save_dir); - _paths.scenario_dir = str_fmt("%sscenario", cfg); - _paths.heightmap_dir = str_fmt("%sscenario\\heightmap", cfg); - _paths.gm_dir = str_fmt("%sgm\\", cfg); - _paths.data_dir = str_fmt("%sdata\\", cfg); - _paths.lang_dir = str_fmt("%slang\\", cfg); - - if (_config_file == NULL) - _config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir); - - _highscore_file = str_fmt("%shs.dat", _paths.personal_dir); - _log_file = str_fmt("%sopenttd.log", _paths.personal_dir); - - // make (auto)save and scenario folder - CreateDirectoryW(OTTD2FS(_paths.save_dir), NULL); - CreateDirectoryW(OTTD2FS(_paths.autosave_dir), NULL); - CreateDirectoryW(OTTD2FS(_paths.scenario_dir), NULL); - CreateDirectoryW(OTTD2FS(_paths.heightmap_dir), NULL); -} - -/** - * Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard - * and append this up to the maximum length (either absolute or screenlength). If maxlength - * is zero, we don't care about the screenlength but only about the physical length of the string - * @param tb @Textbuf type to be changed - * @return Return true on successfull change of Textbuf, or false otherwise - */ -bool InsertTextBufferClipboard(Textbuf *tb) -{ - HGLOBAL cbuf; - char utf8_buf[512]; - const char *ptr; - - WChar c; - uint16 width, length; - - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { - const char *ret; - - OpenClipboard(NULL); - cbuf = GetClipboardData(CF_UNICODETEXT); - - ptr = GlobalLock(cbuf); - ret = convert_from_fs((wchar_t*)ptr, utf8_buf, lengthof(utf8_buf)); - GlobalUnlock(cbuf); - CloseClipboard(); - - if (*ret == '\0') return false; - } else if (IsClipboardFormatAvailable(CF_TEXT)) { - OpenClipboard(NULL); - cbuf = GetClipboardData(CF_TEXT); - - ptr = GlobalLock(cbuf); - ttd_strlcpy(utf8_buf, ptr, lengthof(utf8_buf)); - GlobalUnlock(cbuf); - CloseClipboard(); - } else { - return false; - } - - width = length = 0; - - for (ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) { - byte charwidth; - - if (!IsPrintable(c)) break; - if (tb->length + length >= tb->maxlength - 1) break; - charwidth = GetCharacterWidth(FS_NORMAL, c); - - if (tb->maxwidth != 0 && width + tb->width + charwidth > tb->maxwidth) break; - - width += charwidth; - length += Utf8CharLen(c); - } - - if (length == 0) return false; - - memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos); - memcpy(tb->buf + tb->caretpos, utf8_buf, length); - tb->width += width; - tb->caretxoffs += width; - - tb->length += length; - tb->caretpos += length; - tb->buf[tb->length] = '\0'; // terminating zero - - return true; -} - - -void CSleep(int milliseconds) -{ - Sleep(milliseconds); -} - - -// Utility function to get the current timestamp in milliseconds -// Useful for profiling -int64 GetTS(void) -{ - static double freq; - __int64 value; - if (!freq) { - QueryPerformanceFrequency((LARGE_INTEGER*)&value); - freq = (double)1000000 / value; - } - QueryPerformanceCounter((LARGE_INTEGER*)&value); - return (__int64)(value * freq); -} - -/** Convert from OpenTTD's encoding to that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char - * @param name pointer to a valid string that will be converted - * @param utf16_buf pointer to a valid wide-char buffer that will receive the - * converted string - * @param buflen length in wide characters of the receiving buffer - * @return pointer to utf16_buf. If conversion fails the string is of zero-length */ -wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen) -{ - int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, buflen); - if (len == 0) { - DEBUG(misc, 0, "[utf8] error converting '%s'. Errno %d", name, GetLastError()); - utf16_buf[0] = '\0'; - } - - return utf16_buf; -} - -/** Convert from OpenTTD's encoding to that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char. - * The returned value's contents can only be guaranteed until the next call to - * this function. So if the value is needed for anything else, use convert_from_fs - * @param name pointer to a valid string that will be converted - * @return pointer to the converted string; if failed string is of zero-length */ -const wchar_t *OTTD2FS(const char *name) -{ - static wchar_t utf16_buf[512]; - return convert_to_fs(name, utf16_buf, lengthof(utf16_buf)); -} - - -/** Convert to OpenTTD's encoding from that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char - * @param name pointer to a valid string that will be converted - * @param utf8_buf pointer to a valid buffer that will receive the converted string - * @param buflen length in characters of the receiving buffer - * @return pointer to utf8_buf. If conversion fails the string is of zero-length */ -char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen) -{ - int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, buflen, NULL, NULL); - if (len == 0) { - DEBUG(misc, 0, "[utf8] error converting wide-string. Errno %d", GetLastError()); - utf8_buf[0] = '\0'; - } - - return utf8_buf; -} - -/** Convert to OpenTTD's encoding from that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char. - * The returned value's contents can only be guaranteed until the next call to - * this function. So if the value is needed for anything else, use convert_from_fs - * @param name pointer to a valid string that will be converted - * @return pointer to the converted string; if failed string is of zero-length */ -const char *FS2OTTD(const wchar_t *name) -{ - static char utf8_buf[512]; - return convert_from_fs(name, utf8_buf, lengthof(utf8_buf)); -} - -/** Our very own SHGetFolderPath function for support of windows operating - * systems that don't have this function (eg Win9x, etc.). We try using the - * native function, and if that doesn't exist we will try a more crude approach - * of environment variables and hope for the best */ -HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath) -{ - static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL; - static bool first_time = true; - - /* We only try to load the library one time; if it fails, it fails */ - if (first_time) { -#if defined(UNICODE) -# define W(x) x "W" -#else -# define W(x) x "A" -#endif - if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) { - DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from SHFolder.dll"); - } -#undef W - first_time = false; - } - - if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath); - - /* SHGetFolderPath doesn't exist, try a more conservative approach, - * eg environment variables. This is only included for legacy modes - * MSDN says: that 'pszPath' is a "Pointer to a null-terminated string of - * length MAX_PATH which will receive the path" so let's assume that - * Windows 95 with Internet Explorer 5.0, Windows 98 with Internet Explorer 5.0, - * Windows 98 Second Edition (SE), Windows NT 4.0 with Internet Explorer 5.0, - * Windows NT 4.0 with Service Pack 4 (SP4) */ - { - DWORD ret; - switch (csidl) { - case CSIDL_FONTS: /* Get the system font path, eg %WINDIR%\Fonts */ - ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH); - if (ret == 0) break; - _tcsncat(pszPath, _T("\\Fonts"), MAX_PATH); - - return (HRESULT)0; - break; - /* XXX - other types to go here when needed... */ - } - } - - return E_INVALIDARG; -} |