12 #include "../../stdafx.h" 
   13 #include "../../debug.h" 
   14 #include "../../gfx_func.h" 
   15 #include "../../textbuf_gui.h" 
   16 #include "../../fileio_func.h" 
   23 #include "../../fios.h" 
   24 #include "../../core/alloc_func.hpp" 
   25 #include "../../openttd.h" 
   26 #include "../../core/random_func.hpp" 
   27 #include "../../string_func.h" 
   28 #include "../../crashlog.h" 
   33 #include "../../safeguards.h" 
   37 static bool _has_console;
 
   38 static bool _cursor_disable = 
true;
 
   39 static bool _cursor_visible = 
true;
 
   41 bool MyShowCursor(
bool show, 
bool toggle)
 
   43   if (toggle) _cursor_disable = !_cursor_disable;
 
   44   if (_cursor_disable) 
return show;
 
   45   if (_cursor_visible == show) 
return show;
 
   47   _cursor_visible = show;
 
   60   while (*dll != 
'\0') {
 
   62     lib = LoadLibrary(MB_TO_WIDE(dll));
 
   64     if (lib == NULL) 
return false;
 
   68       while (*dll++ != 
'\0') {  }
 
   69       if (*dll == 
'\0') 
break;
 
   71       p = GetProcAddress(lib, MB_TO_WIDE(dll));
 
   73       p = GetProcAddress(lib, dll);
 
   75       if (p == NULL) 
return false;
 
   76       *proc++ = (Function)p;
 
   83 void ShowOSErrorBox(
const char *buf, 
bool system)
 
   86   MessageBox(GetActiveWindow(), 
OTTD2FS(buf), _T(
"Error!"), MB_ICONSTOP);
 
   89 void OSOpenBrowser(
const char *url)
 
   91   ShellExecute(GetActiveWindow(), _T(
"open"), 
OTTD2FS(url), NULL, NULL, SW_SHOWNORMAL);
 
  116 static DIR _global_dir;
 
  117 static LONG _global_dir_is_in_use = 
false;
 
  119 static inline DIR *dir_calloc()
 
  123   if (InterlockedExchange(&_global_dir_is_in_use, 
true) == (LONG)
true) {
 
  127     memset(d, 0, 
sizeof(*d));
 
  132 static inline void dir_free(
DIR *d)
 
  134   if (d == &_global_dir) {
 
  135     _global_dir_is_in_use = (LONG)
false;
 
  141 DIR *opendir(
const TCHAR *path)
 
  144   UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); 
 
  145   DWORD fa = GetFileAttributes(path);
 
  147   if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
 
  150       TCHAR search_path[MAX_PATH];
 
  151       bool slash = path[_tcslen(path) - 1] == 
'\\';
 
  155       _sntprintf(search_path, 
lengthof(search_path), _T(
"%s%s*"), path, slash ? _T(
"") : _T(
"\\"));
 
  156       *
lastof(search_path) = 
'\0';
 
  157       d->hFind = FindFirstFile(search_path, &d->fd);
 
  159       if (d->hFind != INVALID_HANDLE_VALUE ||
 
  160           GetLastError() == ERROR_NO_MORE_FILES) { 
 
  162         d->at_first_entry = 
true;
 
  180 struct dirent *readdir(
DIR *d)
 
  182   DWORD prev_err = GetLastError(); 
 
  184   if (d->at_first_entry) {
 
  186     if (d->hFind == INVALID_HANDLE_VALUE) 
return NULL;
 
  187     d->at_first_entry = 
false;
 
  188   } 
else if (!FindNextFile(d->hFind, &d->fd)) { 
 
  189     if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
 
  195   d->ent.d_name = d->fd.cFileName;
 
  206 bool FiosIsRoot(
const char *file)
 
  208   return file[3] == 
'\0'; 
 
  211 void FiosGetDrives(
FileList &file_list)
 
  216   fios->type = FIOS_TYPE_DRIVE;
 
  224   GetLogicalDriveStrings(
lengthof(drives), drives);
 
  225   for (s = drives; *s != 
'\0';) {
 
  227     fios->type = FIOS_TYPE_DRIVE;
 
  231     while (*s++ != 
'\0') {  }
 
  236 bool FiosIsValidFile(
const char *path, 
const struct dirent *ent, 
struct stat *sb)
 
  239   static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
 
  240   const WIN32_FIND_DATA *fd = &ent->dir->fd;
 
  242   sb->st_size  = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
 
  248   sb->st_mtime = (time_t)((*(
const uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
 
  249   sb->st_mode  = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
 
  254 bool FiosIsHiddenFile(
const struct dirent *ent)
 
  256   return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
 
  259 bool FiosGetDiskFreeSpace(
const char *path, uint64 *tot)
 
  261   UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);  
 
  264   DWORD spc, bps, nfc, tnc;
 
  266   _sntprintf(root, 
lengthof(root), _T(
"%c:") _T(PATHSEP), path[0]);
 
  267   if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
 
  268     *tot = ((spc * bps) * (uint64)nfc);
 
  276 static int ParseCommandLine(
char *line, 
char **argv, 
int max_argc)
 
  282     while (*line == 
' ' || *line == 
'\t') line++;
 
  285     if (*line == 
'\0') 
break;
 
  290       while (*line != 
'"') {
 
  291         if (*line == 
'\0') 
return n;
 
  296       while (*line != 
' ' && *line != 
'\t') {
 
  297         if (*line == 
'\0') 
return n;
 
  302   } 
while (n != max_argc);
 
  313   CONSOLE_SCREEN_BUFFER_INFO coninfo;
 
  315   if (_has_console) 
return;
 
  320   hand = GetStdHandle(STD_OUTPUT_HANDLE);
 
  321   GetConsoleScreenBufferInfo(hand, &coninfo);
 
  322   coninfo.dwSize.Y = 500;
 
  323   SetConsoleScreenBufferSize(hand, coninfo.dwSize);
 
  326 #if !defined(__CYGWIN__) 
  329   int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
 
  333     _has_console = 
false;
 
  337     ShowInfo(
"Unable to open an output handle to the console. Check known-bugs.txt for details.");
 
  341 #if defined(_MSC_VER) && _MSC_VER >= 1900 
  342   freopen(
"CONOUT$", 
"a", stdout);
 
  343   freopen(
"CONIN$", 
"r", stdin);
 
  344   freopen(
"CONOUT$", 
"a", stderr);
 
  346   *stdout = *_fdopen(fd, 
"w");
 
  347   *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), 
"r" );
 
  348   *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), 
"w" );
 
  353   *stdout = *fdopen(1, 
"w" );
 
  354   *stdin = *fdopen(0, 
"r" );
 
  355   *stderr = *fdopen(2, 
"w" );
 
  358   setvbuf(stdin, NULL, _IONBF, 0);
 
  359   setvbuf(stdout, NULL, _IONBF, 0);
 
  360   setvbuf(stderr, NULL, _IONBF, 0);
 
  368 static INT_PTR CALLBACK 
HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
  371     case WM_INITDIALOG: {
 
  375       while (q != 
lastof(help_msg) && *p != 
'\0') {
 
  378           if (q == 
lastof(help_msg)) {
 
  388       TCHAR help_msg_buf[8192];
 
  390       SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
 
  394       if (wParam == 12) ExitProcess(0);
 
  403 void ShowInfo(
const char *str)
 
  406     fprintf(stderr, 
"%s\n", str);
 
  412     old = MyShowCursor(
true);
 
  413     if (strlen(str) > 2048) {
 
  418       DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, 
HelpDialogFunc);
 
  422       TCHAR help_msg_buf[8192];
 
  423       MessageBox(GetActiveWindow(), 
convert_to_fs(str, help_msg_buf, 
lengthof(help_msg_buf)), _T(
"OpenTTD"), MB_ICONINFORMATION | MB_OK);
 
  430 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, 
int nCmdShow)
 
  432 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, 
int nCmdShow)
 
  440 #if defined(UNICODE) && !defined(WINCE) 
  442   if (
HasBit(GetVersion(), 31)) 
usererror(
"This version of OpenTTD doesn't run on windows 95/98/ME.\nPlease download the win9x binary and try again.");
 
  455   _set_error_mode(_OUT_TO_MSGBOX); 
 
  461   argc = ParseCommandLine(cmdline, argv, 
lengthof(argv));
 
  472 void GetCurrentDirectoryW(
int length, 
wchar_t *path)
 
  475   GetModuleFileName(NULL, path, length);
 
  478   wchar_t *pDest = wcsrchr(path, 
'\\');
 
  480     int result = pDest - path + 1;
 
  486 char *getcwd(
char *buf, 
size_t size)
 
  489   TCHAR path[MAX_PATH];
 
  490   GetModuleFileName(NULL, path, MAX_PATH);
 
  493   char *p = strrchr(buf, 
'\\');
 
  494   if (p != NULL) *p = 
'\0';
 
  496   TCHAR path[MAX_PATH];
 
  497   GetCurrentDirectory(MAX_PATH - 1, path);
 
  507   TCHAR path[MAX_PATH];
 
  508 #ifdef WITH_PERSONAL_DIR 
  509   if (SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))) {
 
  519   if (SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))) {
 
  538   if (!GetModuleFileName(NULL, path, 
lengthof(path))) {
 
  539     DEBUG(misc, 0, 
"GetModuleFileName failed (%lu)\n", GetLastError());
 
  542     TCHAR exec_dir[MAX_PATH];
 
  544     if (!GetFullPathName(path, 
lengthof(exec_dir), exec_dir, NULL)) {
 
  545       DEBUG(misc, 0, 
"GetFullPathName failed (%lu)\n", GetLastError());
 
  549       char *s = strrchr(tmp, PATHSEPCHAR);
 
  565   if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
 
  567     cbuf = GetClipboardData(CF_UNICODETEXT);
 
  569     ptr = (
const char*)GlobalLock(cbuf);
 
  570     int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1, NULL, NULL);
 
  574     if (out_len == 0) 
return false;
 
  575 #if !defined(UNICODE) 
  576   } 
else if (IsClipboardFormatAvailable(CF_TEXT)) {
 
  578     cbuf = GetClipboardData(CF_TEXT);
 
  580     ptr = (
const char*)GlobalLock(cbuf);
 
  594 void CSleep(
int milliseconds)
 
  615   static char utf8_buf[512];
 
  631 const TCHAR *
OTTD2FS(
const char *name, 
bool console_cp)
 
  633   static TCHAR system_buf[512];
 
  649   const WCHAR *wide_buf = name;
 
  652   int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
 
  658   WCHAR *wide_buf = 
AllocaM(WCHAR, wide_len);
 
  659   MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
 
  663   int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (
int)buflen, NULL, NULL);
 
  664   if (len == 0) utf8_buf[0] = 
'\0';
 
  680 TCHAR *
convert_to_fs(
const char *name, TCHAR *system_buf, 
size_t buflen, 
bool console_cp)
 
  683   int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (
int)buflen);
 
  684   if (len == 0) system_buf[0] = 
'\0';
 
  686   int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
 
  688     system_buf[0] = 
'\0';
 
  692   WCHAR *wide_buf = 
AllocaM(WCHAR, len);
 
  693   MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
 
  695   len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (
int)buflen, NULL, NULL);
 
  696   if (len == 0) system_buf[0] = 
'\0';
 
  710   static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
 
  711   static bool first_time = 
true;
 
  721     if (!
LoadLibraryList((Function*)&SHGetFolderPath, 
"shell32.dll\0" W(
"SHGetFolderPath") 
"\0\0")) {
 
  722       if (!
LoadLibraryList((Function*)&SHGetFolderPath, 
"SHFolder.dll\0" W(
"SHGetFolderPath") 
"\0\0")) {
 
  723         DEBUG(misc, 0, 
"Unable to load " W(
"SHGetFolderPath") 
"from either shell32.dll or SHFolder.dll");
 
  730   if (SHGetFolderPath != NULL) 
return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
 
  743         ret = GetEnvironmentVariable(_T(
"WINDIR"), pszPath, MAX_PATH);
 
  745         _tcsncat(pszPath, _T(
"\\Fonts"), MAX_PATH);
 
  750       case CSIDL_COMMON_DOCUMENTS: {
 
  752         if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS) 
break;
 
  753         DWORD len = MAX_PATH;
 
  754         ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T(
"Personal") : _T(
"Common Documents"), NULL, NULL, (LPBYTE)pszPath, &len);
 
  756         if (ret == ERROR_SUCCESS) 
return (HRESULT)0;
 
  770   char lang[9], country[9];
 
  771   if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, 
lengthof(lang)) == 0 ||
 
  772       GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, 
lengthof(country)) == 0) {
 
  777   static char retbuf[6] = {lang[0], lang[1], 
'_', country[0], country[1], 0};
 
  785   GetSystemInfo(&info);
 
  786   return info.dwNumberOfProcessors;
 
  791 const DWORD MS_VC_EXCEPTION = 0x406D1388;
 
  804 void SetWin32ThreadName(DWORD dwThreadID, 
const char* threadName)
 
  806   THREADNAME_INFO info;
 
  807   info.dwType = 0x1000;
 
  808   info.szName = threadName;
 
  809   info.dwThreadID = dwThreadID;
 
  812 #pragma warning(push) 
  813 #pragma warning(disable: 6320 6322) 
  815     RaiseException(MS_VC_EXCEPTION, 0, 
sizeof(info) / 
sizeof(ULONG_PTR), (ULONG_PTR*)&info);
 
  816   } __except (EXCEPTION_EXECUTE_HANDLER) {