diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47ca9ed18..2a300ca81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,3 +151,38 @@ jobs: name: 3DMMEx Windows x64 path: | dist/x64-clangcl-relwithdebinfo + + compile-gcc-x86_64-linux-release: + name: Linux gcc x86_64 Debug + runs-on: ubuntu-latest + steps: + - name: Install Packages + run: | + sudo apt-get update && + sudo apt-get install -y g++ cmake libsdl2-dev libsdl2-ttf-dev libgtk-3-dev zenity ninja-build + - name: Check out repository code + uses: actions/checkout@v4 + - name: CMake Generate + run: | + cmake --preset sdl-x86_64-gcc-linux-debug + - name: CMake Build + run: | + cmake --build build/sdl-x86_64-gcc-linux-debug --target tools studio tests + - name: Run tests + run: | + ctest --test-dir build/sdl-x86_64-gcc-linux-debug --output-on-failure --timeout 60 + - name: CMake Install + run: | + cmake --install build/sdl-x86_64-gcc-linux-debug --prefix dist/sdl-x86_64-gcc-linux-debug + - name: Upload debug files + uses: actions/upload-artifact@v4 + with: + name: 3DMMEx Linux gcc x86_64 debug files + path: | + build/sdl-x86_64-gcc-linux-debug/src/chomp/studio/*.i + - name: Upload Debug + uses: actions/upload-artifact@v4 + with: + name: 3DMMEx Linux gcc x86_64 Debug + path: | + dist/sdl-x86_64-gcc-linux-debug diff --git a/CMakePresets.json b/CMakePresets.json index eca7026e0..74380296c 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -184,6 +184,24 @@ "CMAKE_BUILD_TYPE": "Debug", "3DMM_GUI": "SDL" } + }, + { + "displayName": "SDL Linux gcc x64_64 Debug", + "name": "sdl-x86_64-gcc-linux-debug", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "3DMM_GUI": "SDL" + } + }, + { + "displayName": "SDL Linux gcc x64_64 Release", + "name": "sdl-x86_64-gcc-linux-release", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "3DMM_GUI": "SDL" + } } ] -} \ No newline at end of file +} diff --git a/bren/stdmem.c b/bren/stdmemwin.c similarity index 100% rename from bren/stdmem.c rename to bren/stdmemwin.c diff --git a/bren/tmap.cpp b/bren/tmap.cpp index 1131ea207..c4aa75afe 100644 --- a/bren/tmap.cpp +++ b/bren/tmap.cpp @@ -158,7 +158,7 @@ bool TMAP::FWrite(PBLCK pblck) return fTrue; } -#ifdef WIN +#ifndef MAC #define CALCDIST(bRed1, bGreen1, bBlue1, bRed2, bGreen2, bBlue2) \ (((bRed1) - (bRed2)) * ((bRed1) - (bRed2)) + ((bGreen1) - (bGreen2)) * ((bGreen1) - (bGreen2)) + \ @@ -255,7 +255,7 @@ PTMAP TMAP::PtmapReadNative(FNI *pfni, PGL pglclr) pglCache->Put(prgb[iprgb], &iclrBest); } - prgb[iprgb] = (BYTE)iclrBest; + prgb[iprgb] = (uint8_t)iclrBest; } } @@ -269,9 +269,7 @@ PTMAP TMAP::PtmapReadNative(FNI *pfni, PGL pglclr) return ptmap; } -#endif // WIN - -#ifdef MAC +#else // !MAC PTMAP TMAP::PtmapReadNative(FNI *pfni) { RawRtn(); // REVIEW peted: NYI diff --git a/inc/soc.h b/inc/soc.h index 9060693ed..bd6d86c3c 100644 --- a/inc/soc.h +++ b/inc/soc.h @@ -93,11 +93,19 @@ #define khidMsqClock khidLimKidFrame + 4 // khidStudio khidLimKidFrame + 5 Defined in stdiodef.h -#define kftgChunky MacWin(KLCONST4('c', 'h', 'n', 'k'), KLCONST3('c', 'h', 'k')) -#define kftgContent MacWin(KLCONST4('3', 'c', 'o', 'n'), KLCONST3('3', 'c', 'n')) -#define kftgThumbDesc MacWin(KLCONST4('3', 't', 'h', 'd'), KLCONST3('3', 't', 'h')) -#define kftg3mm MacWin(KLCONST3('3', 'm', 'm'), KLCONST3('3', 'm', 'm')) -#define kftgSocTemp MacWin(KLCONST4('3', 't', 'm', 'p'), KLCONST3('3', 't', 'p')) +#ifdef MAC +#define kftgChunky KLCONST4('c', 'h', 'n', 'k') +#define kftgContent KLCONST4('3', 'c', 'o', 'n') +#define kftgThumbDesc KLCONST4('3', 't', 'h', 'd') +#define kftg3mm KLCONST3('3', 'm', 'm') +#define kftgSocTemp KLCONST4('3', 't', 'm', 'p') +#else +#define kftgChunky KLCONST3('c', 'h', 'k') +#define kftgContent KLCONST3('3', 'c', 'n') +#define kftgThumbDesc KLCONST3('3', 't', 'h') +#define kftg3mm KLCONST3('3', 'm', 'm') +#define kftgSocTemp KLCONST3('3', 't', 'p') +#endif #define ksz3mm PszLit("3mm") diff --git a/inc/utest.h b/inc/utest.h index 1a58716d6..6e017a25c 100644 --- a/inc/utest.h +++ b/inc/utest.h @@ -213,7 +213,7 @@ class APP : public APP_PAR bool _FInitBuilding(void); bool _FInitStudio(PFNI pfniUserDoc, bool fFailIfDocOpenFailed = fTrue); bool _FInitAcceleratorTable(void); - void _GetWindowProps(int32_t *pxp, int32_t *pyp, int32_t *pdxp, int32_t *pdyp, DWORD *pdwStyle); + void _GetWindowProps(int32_t *pxp, int32_t *pyp, int32_t *pdxp, int32_t *pdyp, uint32_t *pdwStyle); void _RebuildMainWindow(void); bool _FSwitch640480(bool fTo640480); bool _FDisplayIs640480(void); diff --git a/kauai/CMakeLists.txt b/kauai/CMakeLists.txt index 29703c142..024b9ff8b 100644 --- a/kauai/CMakeLists.txt +++ b/kauai/CMakeLists.txt @@ -617,7 +617,10 @@ if (BUILD_TESTS) target_link_libraries( KauaiGuiTest PUBLIC + KauaiBase + KauaiFile KauaiTestLib + KauaiGroup KauaiGui KauaiRichText GTest::gtest_main diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index 7ee9a824c..159a67ea3 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -10,7 +10,6 @@ #include "frame.h" #include "fcntl.h" #include "stdio.h" -#include "io.h" ASSERTNAME @@ -837,4 +836,4 @@ int32_t APPB::Win32VkFromVk(int32_t vk) } return vk; -} \ No newline at end of file +} diff --git a/kauai/src/fni.h b/kauai/src/fni.h index db5feea61..2bb3395da 100644 --- a/kauai/src/fni.h +++ b/kauai/src/fni.h @@ -127,6 +127,7 @@ class FNI : public FNI_PAR tribool TExists(void); bool FDelete(void); + bool FIsReadOnly(void); bool FRename(PFNI pfniNew); bool FEqual(PFNI pfni); diff --git a/kauai/src/fniposix.cpp b/kauai/src/fniposix.cpp index b1f46ce5d..036cd863d 100644 --- a/kauai/src/fniposix.cpp +++ b/kauai/src/fniposix.cpp @@ -429,6 +429,19 @@ bool FNI::FDelete(void) return fFalse; } +/*************************************************************************** + Return whether the fni is read-only. +***************************************************************************/ +bool FNI::FIsReadOnly(void) +{ + AssertThis(ffniFile); + fs::perms perms; + + perms = fs::status(_stnFile.Psz()).permissions(); + + return ((perms & fs::perms::owner_write) == fs::perms::none); +} + /*************************************************************************** Renames the file indicated by this to *pfni. ***************************************************************************/ @@ -436,10 +449,8 @@ bool FNI::FRename(FNI *pfni) { AssertThis(ffniFile); AssertPo(pfni, ffniFile); - fs::perms perms; - perms = fs::status(_stnFile.Psz()).permissions(); - if (!((perms & fs::perms::owner_write) == fs::perms::none)) + if (!FIsReadOnly()) { fs::path src = fs::path(_stnFile.Psz()); fs::path dst = fs::path(pfni->_stnFile.Psz()); diff --git a/kauai/src/fniwin.cpp b/kauai/src/fniwin.cpp index 28bf8bc62..a5fcd473d 100644 --- a/kauai/src/fniwin.cpp +++ b/kauai/src/fniwin.cpp @@ -527,6 +527,16 @@ bool FNI::FDelete(void) return fFalse; } +/*************************************************************************** + Return whether the fni is read-only. +***************************************************************************/ +bool FNI::FIsReadOnly(void) +{ + AssertThis(ffniFile); + + return (FILE_ATTRIBUTE_READONLY & GetFileAttributes(_stnFile.Psz())); +} + /*************************************************************************** Renames the file indicated by this to *pfni. ***************************************************************************/ @@ -535,8 +545,7 @@ bool FNI::FRename(FNI *pfni) AssertThis(ffniFile); AssertPo(pfni, ffniFile); - if (!(FILE_ATTRIBUTE_READONLY & GetFileAttributes(_stnFile.Psz())) && - MoveFile(_stnFile.Psz(), pfni->_stnFile.Psz())) + if (!FIsReadOnly() && MoveFile(_stnFile.Psz(), pfni->_stnFile.Psz())) { return fTrue; } diff --git a/kauai/src/platform.h b/kauai/src/platform.h index 5cce3ac6d..97694e34b 100644 --- a/kauai/src/platform.h +++ b/kauai/src/platform.h @@ -44,6 +44,16 @@ extern uint32_t DtsCaret(void); Current executable name ****************************************/ extern void GetExecutableName(char *psz, int cchMax); + +/**************************************** + Get environment variable +****************************************/ +extern uint32_t GetEnvironmentVariable(const char *pcszName, char *pszValue, uint32_t cchMax); + +/**************************************** + Current username +****************************************/ +extern bool GetUserName(char *psz, int cchMax); #endif #endif //! PLATFORM_H diff --git a/kauai/src/platlinux.cpp b/kauai/src/platlinux.cpp index 450b8151d..f985afe54 100644 --- a/kauai/src/platlinux.cpp +++ b/kauai/src/platlinux.cpp @@ -4,6 +4,7 @@ #include "platform.h" #include +#include #include #include #include @@ -98,3 +99,43 @@ void GetExecutableName(char *psz, int cchMax) len = ::readlink("/proc/self/exe", psz, cchMax - 1); psz[len] = '\0'; } + +/**************************************** + Get environment variable +****************************************/ +uint32_t GetEnvironmentVariable(const char *pcszName, char *pszValue, uint32_t cchMax) +{ + char *psz = getenv(pcszName); + size_t ilen; + + if (psz == NULL) + { + return 0; + } + + ilen = strlen(psz); + if (ilen > cchMax) + { + ilen = cchMax; + } + + memcpy(pszValue, psz, ilen); + pszValue[ilen] = '\0'; + return ilen; +} + +/**************************************** + Current username +****************************************/ +bool GetUserName(char *psz, int cchMax) +{ + int ires; + + ires = getlogin_r(psz, cchMax); + if (ires != 0) + { + return false; + } + + return true; +} diff --git a/kauai/src/utilstr.cpp b/kauai/src/utilstr.cpp index fb2e9167a..09b969a96 100644 --- a/kauai/src/utilstr.cpp +++ b/kauai/src/utilstr.cpp @@ -13,6 +13,7 @@ #include "util.h" #if !defined(MAC) && !defined(WIN) #include +#include #endif ASSERTNAME @@ -168,9 +169,27 @@ void STN::SetUtf8Sz(PU8SZ pu8szSrc) #endif // UNICODE #else // !WIN - // TODO: Set STN from UTF-8 string - RawRtn(); - SetNil(); + int32_t cb; + iconv_t ic; + char szT[kcchMaxSz]; + size_t cch, cchLeft; + char *in_ptr, *out_ptr; + + cch = strlen(pu8szSrc); + cchLeft = kcchMaxSz; + + in_ptr = pu8szSrc; + out_ptr = szT; + + ic = iconv_open("CP1252", "UTF-8"); + iconv(ic, &in_ptr, &cch, &out_ptr, &cchLeft); + iconv_close(ic); + + cb = kcchMaxSz - cchLeft; + Assert(cb != 0, "iconv failed to convert characters"); + szT[cb] = 0; + + SetSz(szT); #endif // WIN } @@ -607,22 +626,22 @@ void STN::GetSzs(PSZS pszs) /*************************************************************************** Get a zero terminated UTF-8 string from this string. ***************************************************************************/ -void STN::GetUtf8Sz(U8SZ pu8sz) +void STN::GetUtf8Sz(PU8SZ pu8sz) { AssertThis(0); AssertPvCb(pu8sz, kcchTotUtf8Sz); -#ifdef WIN32 - int32_t cch; - int32_t cb; - const wchar *pwcsT; - if (Cch() == 0) { pu8sz[0] = 0; return; } +#ifdef WIN32 + int32_t cch; + int32_t cb; + const wchar *pwcsT; + #ifdef UNICODE // The string is already Unicode, so we can convert it directly to UTF-8 pwcsT = Psz(); @@ -647,9 +666,26 @@ void STN::GetUtf8Sz(U8SZ pu8sz) pu8sz[cb] = 0; #else // !WIN32 - // TODO: convert STN to UTF-8 - RawRtn(); - pu8sz[0] = 0; + int32_t cb; + iconv_t ic; + char *pT; + size_t cch, cchLeft; + char *in_ptr, *out_ptr; + + pT = Psz(); + cch = Cch(); + cchLeft = kcchMaxUtf8Sz; + + in_ptr = pT; + out_ptr = pu8sz; + + ic = iconv_open("UTF-8", "CP1252"); + iconv(ic, &in_ptr, &cch, &out_ptr, &cchLeft); + iconv_close(ic); + + cb = kcchMaxUtf8Sz - cchLeft; + Assert(cb != 0, "iconv failed to convert characters"); + pu8sz[cb] = 0; #endif // WIN32 } @@ -1281,9 +1317,24 @@ uint32_t FcmpCompareUserRgch(const achar *prgch1, int32_t cch1, const achar *prg return FcmpCompareRgch(prgch1, cch1, prgch2, cch2); } #else //! WIN - // REVIEW shonk: Mac: implement for real - RawRtn(); - return FcmpCompareRgch(prgch1, cch1, prgch2, cch2); + int res; + + if (grfstn & fstnIgnoreCase) + res = strncasecmp(prgch1, prgch2, kcbMax); + else + res = strncmp(prgch1, prgch2, kcbMax); + + if (res == 0) + return fcmpEq; + else if (res < 0) + return fcmpLt; + else if (res > 0) + return fcmpGt; + else + { + Bug("why did the string comparison fail?"); + return FcmpCompareRgch(prgch1, cch1, prgch2, cch2); + } #endif //! WIN } diff --git a/kauai/test/assert.cpp b/kauai/test/assert.cpp index 4d55df2ed..7ccd3eb44 100644 --- a/kauai/test/assert.cpp +++ b/kauai/test/assert.cpp @@ -2,8 +2,8 @@ * @brief Kauai assert procedures **/ -#include "util.h" #include +#include "util.h" /** * @brief Kauai assertion handler that causes a Google Test failure on assert @@ -34,4 +34,4 @@ void WarnProc(PSZS pszsFile, int32_t lwLine, PSZS pszsMsg) // Log warnings to debugger if attached OutputDebugStringA(pszsMsg); #endif // WIN32 -} \ No newline at end of file +} diff --git a/kauai/test/resources.cpp b/kauai/test/resources.cpp index 46a85bbb2..62a57f6be 100644 --- a/kauai/test/resources.cpp +++ b/kauai/test/resources.cpp @@ -1,5 +1,5 @@ -#include "resources.h" #include +#include "resources.h" ASSERTNAME diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88f0385a1..16ea04e7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,9 +6,10 @@ target_sources(bren "${PROJECT_SOURCE_DIR}/bren/bwld.cpp" "${PROJECT_SOURCE_DIR}/bren/stderr.c" "${PROJECT_SOURCE_DIR}/bren/stdfile.c" - "${PROJECT_SOURCE_DIR}/bren/stdmem.c" "${PROJECT_SOURCE_DIR}/bren/tmap.cpp" "${PROJECT_SOURCE_DIR}/bren/zbmp.cpp" + + $<$:${PROJECT_SOURCE_DIR}/bren/stdmemwin.c> ) target_include_directories(bren PUBLIC "${PROJECT_SOURCE_DIR}/bren/inc") target_link_libraries(bren diff --git a/src/engine/body.cpp b/src/engine/body.cpp index 1da5a0700..ea9b65d56 100644 --- a/src/engine/body.cpp +++ b/src/engine/body.cpp @@ -669,7 +669,7 @@ void BODY::SetHiliteColor(int32_t iclr) { if (_pbmtlHilite != pvNil) { - _pbmtlHilite->index_base = (UCHAR)iclr; + _pbmtlHilite->index_base = (uint8_t)iclr; } } diff --git a/src/engine/movie.cpp b/src/engine/movie.cpp index 931c4cb7e..7c5215bd7 100644 --- a/src/engine/movie.cpp +++ b/src/engine/movie.cpp @@ -241,10 +241,10 @@ bool MVIE::_FSetPfilSave(PFNI pfni) the FIL, since if we didn't, we'll prompt for a new filename later anyway */ pfni->GetStnPath(&stnFile); -#ifdef WIN - _fReadOnly = (((lAttrib = GetFileAttributes(stnFile.Psz())) != 0xFFFFFFFF) && (lAttrib & FILE_ATTRIBUTE_READONLY)); -#else // MAC +#ifdef MAC // MAC RawRtn(); +#else + _fReadOnly = pfni->FIsReadOnly(); #endif return fTrue; } diff --git a/src/engine/msnd.cpp b/src/engine/msnd.cpp index d4dd2b2d2..cde234346 100644 --- a/src/engine/msnd.cpp +++ b/src/engine/msnd.cpp @@ -38,11 +38,13 @@ ON_CID_ME(cidAlarm, &MSQ::FCmdAlarm, pvNil) END_CMD_MAP_NIL() // default sound import format +#ifdef WIN const WORD knSamplesPerSec = 11025; const WORD knAvgBytesPerSec = 11025; const WORD kwBitsPerSample = 8; const WORD knChannels = 1; const WORD knBlockAlign = 1; +#endif /*************************************************************************** diff --git a/src/studio/configstub.cpp b/src/studio/configstub.cpp index 72a306750..0a4423c12 100644 --- a/src/studio/configstub.cpp +++ b/src/studio/configstub.cpp @@ -30,16 +30,16 @@ typedef struct StaticConfigItem_t const StaticConfigItem_t _rgconfig[] = { // Enable better quality rendering - {kszBetterSpeedValue, 0, pvNil, pvNil, 0}, + {kszBetterSpeedValue, "0", pvNil, pvNil, 0}, // Play the startup sound - {kszStartupSoundValue, 1, pvNil, pvNil, 0}, + {kszStartupSoundValue, "1", pvNil, pvNil, 0}, // Enable stereo sound - {kszStereoSound, 1, pvNil, pvNil, 0}, + {kszStereoSound, "1", pvNil, pvNil, 0}, // Enable high quality sound import - {kszHighQualitySoundImport, 1, pvNil, pvNil}, + {kszHighQualitySoundImport, "1", pvNil, pvNil}, }; diff --git a/src/studio/stdiobrw.cpp b/src/studio/stdiobrw.cpp index b56597b11..de8480797 100644 --- a/src/studio/stdiobrw.cpp +++ b/src/studio/stdiobrw.cpp @@ -541,7 +541,7 @@ void BRWM::_ApplySelection(int32_t thumSelect, int32_t sid) PGOK pgok; PMVU pmvu; TAG tag; - BOOL fClick = fTrue; + bool fClick = fTrue; pmvu = (PMVU)(_pstdio->Pmvie()->PddgGet(0)); AssertPo(pmvu, 0); diff --git a/src/studio/utest.cpp b/src/studio/utest.cpp index 078345135..a8d5c5307 100644 --- a/src/studio/utest.cpp +++ b/src/studio/utest.cpp @@ -114,11 +114,19 @@ void APP::Run(uint32_t grfapp, uint32_t grfgob, int32_t ginDef) grfapp |= fappStereoSound; } +#ifdef WIN __try { APP_PAR::Run(grfapp, grfgob, ginDef); } __except (UnhandledExceptionFilter(GetExceptionInformation())) +#else + try + { + APP_PAR::Run(grfapp, grfgob, ginDef); + } + catch (...) +#endif { PDLG pdlg; @@ -942,7 +950,7 @@ bool APP::_FInitOS(void) int32_t dypWindow; int32_t xpWindow; int32_t ypWindow; - DWORD dwStyle = 0; + uint32_t dwStyle = 0; STN stnWindowTitle; if (_fMainWindowCreated) // If someone else called _FInitOS already, @@ -1004,7 +1012,7 @@ bool APP::_FInitOS(void) should pass in the current dwStyle if the window already exists. If the window does not already exist, pass in 0. ***************************************************************************/ -void APP::_GetWindowProps(int32_t *pxp, int32_t *pyp, int32_t *pdxp, int32_t *pdyp, DWORD *pdwStyle) +void APP::_GetWindowProps(int32_t *pxp, int32_t *pyp, int32_t *pdxp, int32_t *pdyp, uint32_t *pdwStyle) { AssertBaseThis(0); AssertVarMem(pxp); @@ -1065,7 +1073,7 @@ void APP::_RebuildMainWindow(void) int32_t dypWindow; int32_t xpWindow; int32_t ypWindow; - DWORD dwStyle; + uint32_t dwStyle; dwStyle = GetWindowLong(vwig.hwndApp, GWL_STYLE); _GetWindowProps(&xpWindow, &ypWindow, &dxpWindow, &dypWindow, &dwStyle); @@ -1313,10 +1321,14 @@ bool APP::_FGetUserName(void) Assert(!fRet || _stnUser.Cch() > 0, "Bug in _FGetUserName"); return fRet; #else // WIN - Bug("FIXME: Implement APP::_FGetUserName"); + char username[kcchMaxSz]; + + if (GetUserName(username, kcchMaxSz)) + _stnUser.SetSz(username); + else + _stnUser = PszLit("User"); // Set a default user name - // Set a default user name - _stnUser = PszLit("User"); + Assert(_stnUser.Cch() > 0, "Bug in _FGetUserName"); return fTrue; #endif // !WIN } @@ -1511,10 +1523,9 @@ bool APP::_FReadTitlesFromReg(PGST *ppgst) SZ szSid; STN stnSid; - DWORD cchSid = kcchMaxSz; + SZ szTitle; STN stnTitle; - DWORD cchTitle = kcchMaxSz; PGST pgst; int32_t sid; @@ -1525,6 +1536,11 @@ bool APP::_FReadTitlesFromReg(PGST *ppgst) HKEY hkey; DWORD dwDisposition; DWORD iValue; + DWORD cchSid; + DWORD cchTitle; + + cchSid = kcchMaxSz; + cchTitle = kcchMaxSz; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, kszProductsKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hkey, &dwDisposition) == ERROR_SUCCESS)