diff --git a/CMakeLists.txt b/CMakeLists.txt index 03b7875..9640369 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,10 @@ PROJECT(mst06_base) CMAKE_MINIMUM_REQUIRED(VERSION 3.1) +LIST(APPEND CMAKE_MODULE_PATH + "${CMAKE_SOURCE_DIR}/cmake/modules" + ) + # If no build type is set, default to "Debug". # TODO: Default to "Release"? STRING(TOLOWER "${CMAKE_BUILD_TYPE}" TMP_BUILD_TYPE) @@ -37,6 +41,31 @@ CONFIGURE_FILE( ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake") +# Windows-specific compile flags. +IF(WIN32) + SET(WIN32_C_FLAGS_COMMON "-DSTRICT -DWIN32_LEAN_AND_MEAN -DNOMINMAX") + + # NOTE: This program only supports Unicode on Windows. + # No support for ANSI Windows, i.e. Win9x. + SET(WIN32_C_FLAGS_COMMON "${WIN32_C_FLAGS_COMMON} -DUNICODE -D_UNICODE") + + # Minimum Windows version for the SDK is Windows 2000. + SET(WIN32_C_FLAGS_COMMON "${WIN32_C_FLAGS_COMMON} -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0500") + + # Enable secure template overloads for C++. + # References: + # - MinGW's _mingw_secapi.h + # - http://msdn.microsoft.com/en-us/library/ms175759%28v=VS.100%29.aspx + SET(WIN32_CXX_FLAGS_COMMON "-D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=1") + SET(WIN32_CXX_FLAGS_COMMON "${WIN32_CXX_FLAGS_COMMON} -D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY=1") + SET(WIN32_CXX_FLAGS_COMMON "${WIN32_CXX_FLAGS_COMMON} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") + SET(WIN32_CXX_FLAGS_COMMON "${WIN32_CXX_FLAGS_COMMON} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") + SET(WIN32_CXX_FLAGS_COMMON "${WIN32_CXX_FLAGS_COMMON} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY=1") + + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WIN32_C_FLAGS_COMMON}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WIN32_C_FLAGS_COMMON} ${WIN32_CXX_FLAGS_COMMON}") +ENDIF(WIN32) + # Disable unnecessary warnings. INCLUDE(CheckCCompilerFlag) IF(MSVC) diff --git a/cmake/modules/SetWindowsEntrypoint.cmake b/cmake/modules/SetWindowsEntrypoint.cmake new file mode 100644 index 0000000..92d2df1 --- /dev/null +++ b/cmake/modules/SetWindowsEntrypoint.cmake @@ -0,0 +1,51 @@ +# Set Windows entrypoint. +# _target: Target. +# _entrypoint: Entry point. (main, wmain, WinMain, wWinMain) +# _setargv: If true, link to setargv.obj/wsetargv.obj in MSVC builds. +FUNCTION(SET_WINDOWS_ENTRYPOINT _target _entrypoint _setargv) +IF(WIN32) + IF(MSVC) + # MSVC automatically prepends an underscore if necessary. + SET(ENTRY_POINT_FLAG "/ENTRY:${_entrypoint}CRTStartup") + IF(_setargv) + IF(_entrypoint MATCHES ^wmain OR _entrypoint MATCHES ^wWinMain) + SET(SETARGV_FLAG "wsetargv.obj") + ELSE() + SET(SETARGV_FLAG "setargv.obj") + ENDIF() + ENDIF(_setargv) + UNSET(UNICODE_FLAG) + ELSE(MSVC) + # MinGW does not automatically prepend an underscore. + # TODO: Does ARM Windows have a leading underscore? + # TODO: _setargv for MinGW. + + # NOTE: MinGW uses separate crt*.o files for Unicode + # instead of a separate entry point. + IF(_entrypoint MATCHES "^w") + SET(UNICODE_FLAG "-municode") + STRING(SUBSTRING "${_entrypoint}" 1 -1 _entrypoint) + ENDIF() + + IF(CPU_i386 OR CPU_amd64) + IF(CMAKE_SIZEOF_VOID_P EQUAL 4) + SET(ENTRY_POINT "_${_entrypoint}CRTStartup") + ELSE() + SET(ENTRY_POINT "${_entrypoint}CRTStartup") + ENDIF() + ELSE() + SET(ENTRY_POINT "${_entrypoint}CRTStartup") + ENDIF(CPU_i386 OR CPU_amd64) + SET(ENTRY_POINT_FLAG "-Wl,-e,${ENTRY_POINT}") + UNSET(SETARGV_FLAG) + ENDIF(MSVC) + + GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${_target} LINK_FLAGS) + IF(TARGET_LINK_FLAGS) + SET(TARGET_LINK_FLAGS "${TARGET_LINK_FLAGS} ${UNICODE_FLAG} ${ENTRY_POINT_FLAG} ${SETARGV_FLAG}") + ELSE() + SET(TARGET_LINK_FLAGS "${UNICODE_FLAG} ${ENTRY_POINT_FLAG} ${SETARGV_FLAG}") + ENDIF() + SET_TARGET_PROPERTIES(${_target} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}") +ENDIF(WIN32) +ENDFUNCTION() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e41314..f450f8d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,3 +23,7 @@ SET(mst06_H ADD_EXECUTABLE(mst06 ${mst06_SRCS} ${mst06_H}) SET_PROPERTY(TARGET mst06 PROPERTY CXX_STANDARD 11) TARGET_INCLUDE_DIRECTORIES(mst06 PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + +# TODO: Enable wildcard expansion on Windows? +INCLUDE(SetWindowsEntrypoint) +SET_WINDOWS_ENTRYPOINT(mst06 wmain OFF) \ No newline at end of file diff --git a/src/mst06.cpp b/src/mst06.cpp index be1010c..3ff5579 100644 --- a/src/mst06.cpp +++ b/src/mst06.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * MST Decoder/Encoder for Sonic '06 * - * main.cpp: Main program. * + * mst06.cpp: Main program. * * * * Copyright (c) 2019 by David Korth. * * * @@ -32,17 +32,18 @@ using std::pair; #include "mst_structs.h" #include "byteswap.h" +#include "tcharx.h" -int main(int argc, char *argv[]) +int _tmain(int argc, TCHAR *argv[]) { if (argc != 2) { - fprintf(stderr, "Syntax: %s mst_file.mst\n", argv[0]); + _ftprintf(stderr, _T("Syntax: %s mst_file.mst\n"), argv[0]); return EXIT_FAILURE; } - FILE *f_mst = fopen(argv[1], "rb"); + FILE *f_mst = _tfopen(argv[1], _T("rb")); if (!f_mst) { - fprintf(stderr, "*** ERROR opening %s: %s\n", argv[1], strerror(errno)); + _ftprintf(stderr, _T("*** ERROR opening %s: %s\n"), argv[1], _tcserror(errno)); return EXIT_FAILURE; } diff --git a/src/tcharx.h b/src/tcharx.h new file mode 100644 index 0000000..7558433 --- /dev/null +++ b/src/tcharx.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * MST Decoder/Encoder for Sonic '06 * + * tcharx.h: TCHAR support for Windows and Linux. * + * * + * Copyright (c) 2018-2019 by David Korth. * + * * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; either version 3 of the License, or (at your * + * option) any later version. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef __MST06_TCHARX_H__ +#define __MST06_TCHARX_H__ + +#ifdef _WIN32 + +// Windows: Use the SDK tchar.h. +#include + +// std::tstring +#ifdef _UNICODE +# define tstring wstring +#else /* !_UNICODE */ +# define tstring string +#endif /* _UNICODE */ + +#else /* !_WIN32 */ + +// Other systems: Define TCHAR and related macros. +typedef char TCHAR; +#define _T(x) x +#define _tmain main +#define tstring string + +// ctype.h +#define _istalpha(c) isalpha(c) + +// stdio.h +#define _fputts(s, stream) fputs(s, stream) + +#define _tfopen(filename, mode) fopen((filename), (mode)) + +#define _tprintf printf +#define _ftprintf fprintf +#define _sntprintf snprintf +#define _vtprintf vprintf +#define _vftprintf vfprintf +#define _vsprintf vsprintf + +// stdlib.h +#define _tcscmp(s1, s2) strcmp((s1), (s2)) +#define _tcsicmp(s1, s2) strcasecmp((s1), (s2)) +#define _tcsnicmp(s1, s2) strncasecmp((s1), (s2), (n)) +#define _tcstoul(nptr, endptr, base) strtoul((nptr), (endptr), (base)) + +// string.h +#define _tcsdup(s) strdup(s) +#define _tcserror(err) strerror(err) + +#endif /* _WIN32 */ + +#endif /* __MST06_TCHARX_H__ */