10 #include "../../stdafx.h" 11 #include "../../debug.h" 12 #include "../../gfx_func.h" 13 #include "../../textbuf_gui.h" 14 #include "../../fileio_func.h" 18 #define NO_SHOBJIDL_SORTDIRECTION // Avoid multiple definition of SORT_ASCENDING 22 #include "../../fios.h" 23 #include "../../core/alloc_func.hpp" 24 #include "../../openttd.h" 25 #include "../../core/random_func.hpp" 26 #include "../../string_func.h" 27 #include "../../crashlog.h" 30 #include "../../language.h" 31 #include "../../thread.h" 33 #include "../../safeguards.h" 35 static bool _has_console;
36 static bool _cursor_disable =
true;
37 static bool _cursor_visible =
true;
39 bool MyShowCursor(
bool show,
bool toggle)
41 if (toggle) _cursor_disable = !_cursor_disable;
42 if (_cursor_disable)
return show;
43 if (_cursor_visible == show)
return show;
45 _cursor_visible = show;
58 while (*dll !=
'\0') {
60 lib = LoadLibrary(MB_TO_WIDE(dll));
62 if (lib ==
nullptr)
return false;
66 while (*dll++ !=
'\0') { }
67 if (*dll ==
'\0')
break;
68 p = GetProcAddress(lib, dll);
69 if (p ==
nullptr)
return false;
70 *proc++ = (Function)p;
77 void ShowOSErrorBox(
const char *buf,
bool system)
80 MessageBox(GetActiveWindow(),
OTTD2FS(buf), _T(
"Error!"), MB_ICONSTOP | MB_TASKMODAL);
83 void OSOpenBrowser(
const char *url)
85 ShellExecute(GetActiveWindow(), _T(
"open"),
OTTD2FS(url),
nullptr,
nullptr, SW_SHOWNORMAL);
110 static DIR _global_dir;
111 static LONG _global_dir_is_in_use =
false;
113 static inline DIR *dir_calloc()
117 if (InterlockedExchange(&_global_dir_is_in_use,
true) == (LONG)
true) {
121 memset(d, 0,
sizeof(*d));
126 static inline void dir_free(
DIR *d)
128 if (d == &_global_dir) {
129 _global_dir_is_in_use = (LONG)
false;
135 DIR *opendir(
const TCHAR *path)
138 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
139 DWORD fa = GetFileAttributes(path);
141 if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
144 TCHAR search_path[MAX_PATH];
145 bool slash = path[_tcslen(path) - 1] ==
'\\';
149 _sntprintf(search_path,
lengthof(search_path), _T(
"%s%s*"), path, slash ? _T(
"") : _T(
"\\"));
150 *
lastof(search_path) =
'\0';
151 d->hFind = FindFirstFile(search_path, &d->fd);
153 if (d->hFind != INVALID_HANDLE_VALUE ||
154 GetLastError() == ERROR_NO_MORE_FILES) {
156 d->at_first_entry =
true;
174 struct dirent *readdir(
DIR *d)
176 DWORD prev_err = GetLastError();
178 if (d->at_first_entry) {
180 if (d->hFind == INVALID_HANDLE_VALUE)
return nullptr;
181 d->at_first_entry =
false;
182 }
else if (!FindNextFile(d->hFind, &d->fd)) {
183 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
189 d->ent.d_name = d->fd.cFileName;
200 bool FiosIsRoot(
const char *file)
202 return file[3] ==
'\0';
205 void FiosGetDrives(
FileList &file_list)
210 GetLogicalDriveStrings(
lengthof(drives), drives);
211 for (s = drives; *s !=
'\0';) {
213 fios->type = FIOS_TYPE_DRIVE;
217 while (*s++ !=
'\0') { }
221 bool FiosIsValidFile(
const char *path,
const struct dirent *ent,
struct stat *sb)
224 static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
225 const WIN32_FIND_DATA *fd = &ent->dir->fd;
227 sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
233 sb->st_mtime = (time_t)((*(
const uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
234 sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
239 bool FiosIsHiddenFile(
const struct dirent *ent)
241 return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
244 bool FiosGetDiskFreeSpace(
const char *path, uint64 *tot)
246 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
249 DWORD spc, bps, nfc, tnc;
251 _sntprintf(root,
lengthof(root), _T(
"%c:") _T(PATHSEP), path[0]);
252 if (tot !=
nullptr && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
253 *tot = ((spc * bps) * (uint64)nfc);
261 static int ParseCommandLine(
char *line,
char **argv,
int max_argc)
267 while (*line ==
' ' || *line ==
'\t') line++;
270 if (*line ==
'\0')
break;
275 while (*line !=
'"') {
276 if (*line ==
'\0')
return n;
281 while (*line !=
' ' && *line !=
'\t') {
282 if (*line ==
'\0')
return n;
287 }
while (n != max_argc);
295 CONSOLE_SCREEN_BUFFER_INFO coninfo;
297 if (_has_console)
return;
300 if (!AllocConsole())
return;
302 hand = GetStdHandle(STD_OUTPUT_HANDLE);
303 GetConsoleScreenBufferInfo(hand, &coninfo);
304 coninfo.dwSize.Y = 500;
305 SetConsoleScreenBufferSize(hand, coninfo.dwSize);
308 #if !defined(__CYGWIN__) 311 int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
315 _has_console =
false;
319 ShowInfo(
"Unable to open an output handle to the console. Check known-bugs.txt for details.");
323 #if defined(_MSC_VER) && _MSC_VER >= 1900 324 freopen(
"CONOUT$",
"a", stdout);
325 freopen(
"CONIN$",
"r", stdin);
326 freopen(
"CONOUT$",
"a", stderr);
328 *stdout = *_fdopen(fd,
"w");
329 *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT),
"r" );
330 *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT),
"w" );
335 *stdout = *fdopen(1,
"w" );
336 *stdin = *fdopen(0,
"r" );
337 *stderr = *fdopen(2,
"w" );
340 setvbuf(stdin,
nullptr, _IONBF, 0);
341 setvbuf(stdout,
nullptr, _IONBF, 0);
342 setvbuf(stderr,
nullptr, _IONBF, 0);
349 static INT_PTR CALLBACK
HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
352 case WM_INITDIALOG: {
356 while (q !=
lastof(help_msg) && *p !=
'\0') {
359 if (q ==
lastof(help_msg)) {
369 TCHAR help_msg_buf[8192];
371 SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
375 if (wParam == 12) ExitProcess(0);
384 void ShowInfo(
const char *str)
387 fprintf(stderr,
"%s\n", str);
393 old = MyShowCursor(
true);
394 if (strlen(str) > 2048) {
399 DialogBox(GetModuleHandle(
nullptr), MAKEINTRESOURCE(101),
nullptr,
HelpDialogFunc);
403 TCHAR help_msg_buf[8192];
404 MessageBox(GetActiveWindow(),
convert_to_fs(str, help_msg_buf,
lengthof(help_msg_buf)), _T(
"OpenTTD"), MB_ICONINFORMATION | MB_OK);
410 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
419 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.");
431 _set_error_mode(_OUT_TO_MSGBOX);
436 argc = ParseCommandLine(cmdline, argv,
lengthof(argv));
446 char *getcwd(
char *buf,
size_t size)
448 TCHAR path[MAX_PATH];
449 GetCurrentDirectory(MAX_PATH - 1, path);
458 TCHAR path[MAX_PATH];
459 #ifdef WITH_PERSONAL_DIR 460 if (SUCCEEDED(
OTTDSHGetFolderPath(
nullptr, CSIDL_PERSONAL,
nullptr, SHGFP_TYPE_CURRENT, path))) {
470 if (SUCCEEDED(
OTTDSHGetFolderPath(
nullptr, CSIDL_COMMON_DOCUMENTS,
nullptr, SHGFP_TYPE_CURRENT, path))) {
489 if (!GetModuleFileName(
nullptr, path,
lengthof(path))) {
490 DEBUG(misc, 0,
"GetModuleFileName failed (%lu)\n", GetLastError());
493 TCHAR exec_dir[MAX_PATH];
495 if (!GetFullPathName(path,
lengthof(exec_dir), exec_dir,
nullptr)) {
496 DEBUG(misc, 0,
"GetFullPathName failed (%lu)\n", GetLastError());
500 char *s = strrchr(tmp, PATHSEPCHAR);
516 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
517 OpenClipboard(
nullptr);
518 cbuf = GetClipboardData(CF_UNICODETEXT);
520 ptr = (
const char*)GlobalLock(cbuf);
521 int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1,
nullptr,
nullptr);
525 if (out_len == 0)
return false;
526 #if !defined(UNICODE) 527 }
else if (IsClipboardFormatAvailable(CF_TEXT)) {
528 OpenClipboard(
nullptr);
529 cbuf = GetClipboardData(CF_TEXT);
531 ptr = (
const char*)GlobalLock(cbuf);
560 static char utf8_buf[512];
576 const TCHAR *
OTTD2FS(
const char *name,
bool console_cp)
578 static TCHAR system_buf[512];
594 const WCHAR *wide_buf = name;
597 int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1,
nullptr, 0);
603 WCHAR *wide_buf =
AllocaM(WCHAR, wide_len);
604 MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
608 int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (
int)buflen,
nullptr,
nullptr);
609 if (len == 0) utf8_buf[0] =
'\0';
625 TCHAR *
convert_to_fs(
const char *name, TCHAR *system_buf,
size_t buflen,
bool console_cp)
628 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (
int)buflen);
629 if (len == 0) system_buf[0] =
'\0';
631 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1,
nullptr, 0);
633 system_buf[0] =
'\0';
637 WCHAR *wide_buf =
AllocaM(WCHAR, len);
638 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
640 len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (
int)buflen,
nullptr,
nullptr);
641 if (len == 0) system_buf[0] =
'\0';
655 static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) =
nullptr;
656 static bool first_time =
true;
666 if (!
LoadLibraryList((Function*)&SHGetFolderPath,
"shell32.dll\0" W(
"SHGetFolderPath")
"\0\0")) {
667 if (!
LoadLibraryList((Function*)&SHGetFolderPath,
"SHFolder.dll\0" W(
"SHGetFolderPath")
"\0\0")) {
668 DEBUG(misc, 0,
"Unable to load " W(
"SHGetFolderPath")
"from either shell32.dll or SHFolder.dll");
675 if (SHGetFolderPath !=
nullptr)
return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
688 ret = GetEnvironmentVariable(_T(
"WINDIR"), pszPath, MAX_PATH);
690 _tcsncat(pszPath, _T(
"\\Fonts"), MAX_PATH);
695 case CSIDL_COMMON_DOCUMENTS: {
697 if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS)
break;
698 DWORD len = MAX_PATH;
699 ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T(
"Personal") : _T(
"Common Documents"),
nullptr,
nullptr, (LPBYTE)pszPath, &len);
701 if (ret == ERROR_SUCCESS)
return (HRESULT)0;
715 char lang[9], country[9];
716 if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang,
lengthof(lang)) == 0 ||
717 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country,
lengthof(country)) == 0) {
722 static char retbuf[6] = {lang[0], lang[1],
'_', country[0], country[1], 0};
727 static WCHAR _cur_iso_locale[16] = L
"";
729 void Win32SetCurrentLocaleName(
const char *iso_code)
733 if (strcmp(iso_code,
"zh_TW") == 0) {
735 }
else if (strcmp(iso_code,
"zh_CN") == 0) {
740 for (
char *c = iso; *c !=
'\0'; c++) {
741 if (*c ==
'_') *c =
'-';
745 MultiByteToWideChar(CP_UTF8, 0, iso, -1, _cur_iso_locale,
lengthof(_cur_iso_locale));
748 int OTTDStringCompare(
const char *s1,
const char *s2)
750 typedef int (WINAPI *PFNCOMPARESTRINGEX)(LPCWSTR, DWORD, LPCWCH, int, LPCWCH, int, LPVOID, LPVOID, LPARAM);
751 static PFNCOMPARESTRINGEX _CompareStringEx =
nullptr;
752 static bool first_time =
true;
754 #ifndef SORT_DIGITSASNUMBERS 755 # define SORT_DIGITSASNUMBERS 0x00000008 // use digits as numbers sort method 757 #ifndef LINGUISTIC_IGNORECASE 758 # define LINGUISTIC_IGNORECASE 0x00000010 // linguistically appropriate 'ignore case' 762 _CompareStringEx = (PFNCOMPARESTRINGEX)GetProcAddress(GetModuleHandle(_T(
"Kernel32")),
"CompareStringEx");
766 if (_CompareStringEx !=
nullptr) {
768 int len_s1 = MultiByteToWideChar(CP_UTF8, 0, s1, -1,
nullptr, 0);
769 int len_s2 = MultiByteToWideChar(CP_UTF8, 0, s2, -1,
nullptr, 0);
771 if (len_s1 != 0 && len_s2 != 0) {
772 LPWSTR str_s1 =
AllocaM(WCHAR, len_s1);
773 LPWSTR str_s2 =
AllocaM(WCHAR, len_s2);
775 MultiByteToWideChar(CP_UTF8, 0, s1, -1, str_s1, len_s1);
776 MultiByteToWideChar(CP_UTF8, 0, s2, -1, str_s2, len_s2);
778 int result = _CompareStringEx(_cur_iso_locale, LINGUISTIC_IGNORECASE | SORT_DIGITSASNUMBERS, str_s1, -1, str_s2, -1,
nullptr,
nullptr, 0);
779 if (result != 0)
return result;
783 TCHAR s1_buf[512], s2_buf[512];
792 const DWORD MS_VC_EXCEPTION = 0x406D1388;
794 PACK_N(
struct THREADNAME_INFO {
806 THREADNAME_INFO info;
807 info.dwType = 0x1000;
808 info.szName = threadName;
809 info.dwThreadID = -1;
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) {
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?
void SetCurrentThreadName(const char *)
Name the thread this function is called on for the debugger.
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...
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.