12 #include "../../stdafx.h" 13 #include "../../debug.h" 14 #include "../../gfx_func.h" 15 #include "../../textbuf_gui.h" 16 #include "../../fileio_func.h" 20 #define NO_SHOBJIDL_SORTDIRECTION // Avoid multiple definition of SORT_ASCENDING 24 #include "../../fios.h" 25 #include "../../core/alloc_func.hpp" 26 #include "../../openttd.h" 27 #include "../../core/random_func.hpp" 28 #include "../../string_func.h" 29 #include "../../crashlog.h" 32 #include "../../language.h" 34 #include "../../safeguards.h" 36 static bool _has_console;
37 static bool _cursor_disable =
true;
38 static bool _cursor_visible =
true;
40 bool MyShowCursor(
bool show,
bool toggle)
42 if (toggle) _cursor_disable = !_cursor_disable;
43 if (_cursor_disable)
return show;
44 if (_cursor_visible == show)
return show;
46 _cursor_visible = show;
59 while (*dll !=
'\0') {
61 lib = LoadLibrary(MB_TO_WIDE(dll));
63 if (lib == NULL)
return false;
67 while (*dll++ !=
'\0') { }
68 if (*dll ==
'\0')
break;
69 p = GetProcAddress(lib, dll);
70 if (p == NULL)
return false;
71 *proc++ = (Function)p;
78 void ShowOSErrorBox(
const char *buf,
bool system)
81 MessageBox(GetActiveWindow(),
OTTD2FS(buf), _T(
"Error!"), MB_ICONSTOP | MB_TASKMODAL);
84 void OSOpenBrowser(
const char *url)
86 ShellExecute(GetActiveWindow(), _T(
"open"),
OTTD2FS(url), NULL, NULL, SW_SHOWNORMAL);
111 static DIR _global_dir;
112 static LONG _global_dir_is_in_use =
false;
114 static inline DIR *dir_calloc()
118 if (InterlockedExchange(&_global_dir_is_in_use,
true) == (LONG)
true) {
122 memset(d, 0,
sizeof(*d));
127 static inline void dir_free(
DIR *d)
129 if (d == &_global_dir) {
130 _global_dir_is_in_use = (LONG)
false;
136 DIR *opendir(
const TCHAR *path)
139 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
140 DWORD fa = GetFileAttributes(path);
142 if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
145 TCHAR search_path[MAX_PATH];
146 bool slash = path[_tcslen(path) - 1] ==
'\\';
150 _sntprintf(search_path,
lengthof(search_path), _T(
"%s%s*"), path, slash ? _T(
"") : _T(
"\\"));
151 *
lastof(search_path) =
'\0';
152 d->hFind = FindFirstFile(search_path, &d->fd);
154 if (d->hFind != INVALID_HANDLE_VALUE ||
155 GetLastError() == ERROR_NO_MORE_FILES) {
157 d->at_first_entry =
true;
175 struct dirent *readdir(
DIR *d)
177 DWORD prev_err = GetLastError();
179 if (d->at_first_entry) {
181 if (d->hFind == INVALID_HANDLE_VALUE)
return NULL;
182 d->at_first_entry =
false;
183 }
else if (!FindNextFile(d->hFind, &d->fd)) {
184 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
190 d->ent.d_name = d->fd.cFileName;
201 bool FiosIsRoot(
const char *file)
203 return file[3] ==
'\0';
206 void FiosGetDrives(
FileList &file_list)
211 GetLogicalDriveStrings(
lengthof(drives), drives);
212 for (s = drives; *s !=
'\0';) {
214 fios->type = FIOS_TYPE_DRIVE;
218 while (*s++ !=
'\0') { }
222 bool FiosIsValidFile(
const char *path,
const struct dirent *ent,
struct stat *sb)
225 static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
226 const WIN32_FIND_DATA *fd = &ent->dir->fd;
228 sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
234 sb->st_mtime = (time_t)((*(
const uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
235 sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
240 bool FiosIsHiddenFile(
const struct dirent *ent)
242 return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
245 bool FiosGetDiskFreeSpace(
const char *path, uint64 *tot)
247 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
250 DWORD spc, bps, nfc, tnc;
252 _sntprintf(root,
lengthof(root), _T(
"%c:") _T(PATHSEP), path[0]);
253 if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
254 *tot = ((spc * bps) * (uint64)nfc);
262 static int ParseCommandLine(
char *line,
char **argv,
int max_argc)
268 while (*line ==
' ' || *line ==
'\t') line++;
271 if (*line ==
'\0')
break;
276 while (*line !=
'"') {
277 if (*line ==
'\0')
return n;
282 while (*line !=
' ' && *line !=
'\t') {
283 if (*line ==
'\0')
return n;
288 }
while (n != max_argc);
296 CONSOLE_SCREEN_BUFFER_INFO coninfo;
298 if (_has_console)
return;
301 if (!AllocConsole())
return;
303 hand = GetStdHandle(STD_OUTPUT_HANDLE);
304 GetConsoleScreenBufferInfo(hand, &coninfo);
305 coninfo.dwSize.Y = 500;
306 SetConsoleScreenBufferSize(hand, coninfo.dwSize);
309 #if !defined(__CYGWIN__) 312 int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
316 _has_console =
false;
320 ShowInfo(
"Unable to open an output handle to the console. Check known-bugs.txt for details.");
324 #if defined(_MSC_VER) && _MSC_VER >= 1900 325 freopen(
"CONOUT$",
"a", stdout);
326 freopen(
"CONIN$",
"r", stdin);
327 freopen(
"CONOUT$",
"a", stderr);
329 *stdout = *_fdopen(fd,
"w");
330 *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT),
"r" );
331 *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT),
"w" );
336 *stdout = *fdopen(1,
"w" );
337 *stdin = *fdopen(0,
"r" );
338 *stderr = *fdopen(2,
"w" );
341 setvbuf(stdin, NULL, _IONBF, 0);
342 setvbuf(stdout, NULL, _IONBF, 0);
343 setvbuf(stderr, NULL, _IONBF, 0);
350 static INT_PTR CALLBACK
HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
353 case WM_INITDIALOG: {
357 while (q !=
lastof(help_msg) && *p !=
'\0') {
360 if (q ==
lastof(help_msg)) {
370 TCHAR help_msg_buf[8192];
372 SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
376 if (wParam == 12) ExitProcess(0);
385 void ShowInfo(
const char *str)
388 fprintf(stderr,
"%s\n", str);
394 old = MyShowCursor(
true);
395 if (strlen(str) > 2048) {
400 DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL,
HelpDialogFunc);
404 TCHAR help_msg_buf[8192];
405 MessageBox(GetActiveWindow(),
convert_to_fs(str, help_msg_buf,
lengthof(help_msg_buf)), _T(
"OpenTTD"), MB_ICONINFORMATION | MB_OK);
411 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
420 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.");
432 _set_error_mode(_OUT_TO_MSGBOX);
437 argc = ParseCommandLine(cmdline, argv,
lengthof(argv));
447 char *getcwd(
char *buf,
size_t size)
449 TCHAR path[MAX_PATH];
450 GetCurrentDirectory(MAX_PATH - 1, path);
459 TCHAR path[MAX_PATH];
460 #ifdef WITH_PERSONAL_DIR 461 if (SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))) {
471 if (SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))) {
490 if (!GetModuleFileName(NULL, path,
lengthof(path))) {
491 DEBUG(misc, 0,
"GetModuleFileName failed (%lu)\n", GetLastError());
494 TCHAR exec_dir[MAX_PATH];
496 if (!GetFullPathName(path,
lengthof(exec_dir), exec_dir, NULL)) {
497 DEBUG(misc, 0,
"GetFullPathName failed (%lu)\n", GetLastError());
501 char *s = strrchr(tmp, PATHSEPCHAR);
517 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
519 cbuf = GetClipboardData(CF_UNICODETEXT);
521 ptr = (
const char*)GlobalLock(cbuf);
522 int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1, NULL, NULL);
526 if (out_len == 0)
return false;
527 #if !defined(UNICODE) 528 }
else if (IsClipboardFormatAvailable(CF_TEXT)) {
530 cbuf = GetClipboardData(CF_TEXT);
532 ptr = (
const char*)GlobalLock(cbuf);
546 void CSleep(
int milliseconds)
567 static char utf8_buf[512];
583 const TCHAR *
OTTD2FS(
const char *name,
bool console_cp)
585 static TCHAR system_buf[512];
601 const WCHAR *wide_buf = name;
604 int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
610 WCHAR *wide_buf =
AllocaM(WCHAR, wide_len);
611 MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
615 int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (
int)buflen, NULL, NULL);
616 if (len == 0) utf8_buf[0] =
'\0';
632 TCHAR *
convert_to_fs(
const char *name, TCHAR *system_buf,
size_t buflen,
bool console_cp)
635 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (
int)buflen);
636 if (len == 0) system_buf[0] =
'\0';
638 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
640 system_buf[0] =
'\0';
644 WCHAR *wide_buf =
AllocaM(WCHAR, len);
645 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
647 len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (
int)buflen, NULL, NULL);
648 if (len == 0) system_buf[0] =
'\0';
662 static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
663 static bool first_time =
true;
673 if (!
LoadLibraryList((Function*)&SHGetFolderPath,
"shell32.dll\0" W(
"SHGetFolderPath")
"\0\0")) {
674 if (!
LoadLibraryList((Function*)&SHGetFolderPath,
"SHFolder.dll\0" W(
"SHGetFolderPath")
"\0\0")) {
675 DEBUG(misc, 0,
"Unable to load " W(
"SHGetFolderPath")
"from either shell32.dll or SHFolder.dll");
682 if (SHGetFolderPath != NULL)
return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
695 ret = GetEnvironmentVariable(_T(
"WINDIR"), pszPath, MAX_PATH);
697 _tcsncat(pszPath, _T(
"\\Fonts"), MAX_PATH);
702 case CSIDL_COMMON_DOCUMENTS: {
704 if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS)
break;
705 DWORD len = MAX_PATH;
706 ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T(
"Personal") : _T(
"Common Documents"), NULL, NULL, (LPBYTE)pszPath, &len);
708 if (ret == ERROR_SUCCESS)
return (HRESULT)0;
722 char lang[9], country[9];
723 if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang,
lengthof(lang)) == 0 ||
724 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country,
lengthof(country)) == 0) {
729 static char retbuf[6] = {lang[0], lang[1],
'_', country[0], country[1], 0};
737 GetSystemInfo(&info);
738 return info.dwNumberOfProcessors;
742 static WCHAR _cur_iso_locale[16] = L
"";
744 void Win32SetCurrentLocaleName(
const char *iso_code)
748 if (strcmp(iso_code,
"zh_TW") == 0) {
750 }
else if (strcmp(iso_code,
"zh_CN") == 0) {
755 for (
char *c = iso; *c !=
'\0'; c++) {
756 if (*c ==
'_') *c =
'-';
760 MultiByteToWideChar(CP_UTF8, 0, iso, -1, _cur_iso_locale,
lengthof(_cur_iso_locale));
763 int OTTDStringCompare(
const char *s1,
const char *s2)
765 typedef int (WINAPI *PFNCOMPARESTRINGEX)(LPCWSTR, DWORD, LPCWCH, int, LPCWCH, int, LPVOID, LPVOID, LPARAM);
766 static PFNCOMPARESTRINGEX _CompareStringEx = NULL;
767 static bool first_time =
true;
769 #ifndef SORT_DIGITSASNUMBERS 770 # define SORT_DIGITSASNUMBERS 0x00000008 // use digits as numbers sort method 772 #ifndef LINGUISTIC_IGNORECASE 773 # define LINGUISTIC_IGNORECASE 0x00000010 // linguistically appropriate 'ignore case' 777 _CompareStringEx = (PFNCOMPARESTRINGEX)GetProcAddress(GetModuleHandle(_T(
"Kernel32")),
"CompareStringEx");
781 if (_CompareStringEx != NULL) {
783 int len_s1 = MultiByteToWideChar(CP_UTF8, 0, s1, -1, NULL, 0);
784 int len_s2 = MultiByteToWideChar(CP_UTF8, 0, s2, -1, NULL, 0);
786 if (len_s1 != 0 && len_s2 != 0) {
787 LPWSTR str_s1 =
AllocaM(WCHAR, len_s1);
788 LPWSTR str_s2 =
AllocaM(WCHAR, len_s2);
790 MultiByteToWideChar(CP_UTF8, 0, s1, -1, str_s1, len_s1);
791 MultiByteToWideChar(CP_UTF8, 0, s2, -1, str_s2, len_s2);
793 int result = _CompareStringEx(_cur_iso_locale, LINGUISTIC_IGNORECASE | SORT_DIGITSASNUMBERS, str_s1, -1, str_s2, -1, NULL, NULL, 0);
794 if (result != 0)
return result;
798 TCHAR s1_buf[512], s2_buf[512];
807 const DWORD MS_VC_EXCEPTION = 0x406D1388;
809 PACK_N(
struct THREADNAME_INFO {
819 void SetWin32ThreadName(DWORD dwThreadID,
const char* threadName)
821 THREADNAME_INFO info;
822 info.dwType = 0x1000;
823 info.szName = threadName;
824 info.dwThreadID = dwThreadID;
827 #pragma warning(push) 828 #pragma warning(disable: 6320 6322) 830 RaiseException(MS_VC_EXCEPTION, 0,
sizeof(info) /
sizeof(ULONG_PTR), (ULONG_PTR*)&info);
831 } __except (EXCEPTION_EXECUTE_HANDLER) {
int openttd_main(int argc, char *argv[])
Main entry point for this lovely game.
static char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
TCHAR * convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool console_cp)
Convert from OpenTTD's encoding to that of the environment in UNICODE.
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD's encoding from that of the local environment.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Search in the directory where the binary resides.
HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
Our very own SHGetFolderPath function for support of windows operating systems that don't have this f...
void SetRandomSeed(uint32 seed)
(Re)set the state of the random number generators.
const LanguageMetadata * _current_language
The currently loaded language.
#define lastof(x)
Get the last element of an fixed size array.
static void InitialiseCrashLog()
Initialiser for crash logs; do the appropriate things so crashes are handled by our crash handler ins...
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
char * convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
const char * GetCurrentLocale(const char *)
Determine the current user's locale.
Deals with finding savegames.
bool _left_button_clicked
Is left mouse button clicked?
bool AppendPathSeparator(char *buf, const char *last)
Appends, if necessary, the path separator character to the end of the string.
bool LoadLibraryList(Function proc[], const char *dll)
Helper function needed by dynamically loading libraries XXX: Hurray for MS only having an ANSI GetPro...
bool _left_button_down
Is left mouse button pressed?
static const char * _help_msg
Temporary pointer to get the help message to the window.
static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
Callback function to handle the window.
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
bool GetClipboardContents(char *buffer, const char *last)
Try to retrieve the current clipboard contents.
#define lengthof(x)
Return the length of an fixed size array.
void DetermineBasePaths(const char *exe)
Determine the base (personal dir and game data dir) paths.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD's encoding to that of the local environment.
#define DEBUG(name, level,...)
Output a line of debugging information.
Search in the personal directory.
List of file information.
const char * _searchpaths[NUM_SEARCHPATHS]
The search paths OpenTTD could search through.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Search in the working directory.
Search in the installation directory.
Search within the application bundle.
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
void ValidateString(const char *str)
Scans the string for valid characters and if it finds invalid ones, replaces them with a question mar...
uint GetCPUCoreCount()
Get number of processor cores in the system, including HyperThreading or similar. ...
FiosItem * Append()
Construct a new entry in the file list.
declarations of functions for MS windows systems
Search in the shared directory, like 'Shared Files' under Windows.