Skip to content

Commit b25b8fe

Browse files
Add big endian support
Co-authored-by: MookThompson <[email protected]>
1 parent bbea05c commit b25b8fe

21 files changed

+220
-30
lines changed

.github/workflows/cmake.yml

+23
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,29 @@ jobs:
6868
shell: bash
6969
run: cmake --build . -j$(nproc)
7070

71+
build-linux-big-endian:
72+
name: Linux (GCC) (Big Endian)
73+
runs-on: ubuntu-20.04
74+
steps:
75+
- uses: actions/checkout@v3
76+
77+
- name: Build in container
78+
uses: uraimo/run-on-arch-action@v2
79+
with:
80+
arch: s390x
81+
distro: alpine_latest
82+
# githubToken: ${{ github.token }}
83+
dockerRunArgs: |
84+
--volume "${PWD}:/app"
85+
env: |
86+
LC_CTYPE: C.UTF-8
87+
shell: /bin/sh
88+
install: apk update && apk add make cmake g++ ncurses-dev gtest-dev linux-headers
89+
run: |
90+
cd /app
91+
cmake . -DCMAKE_BUILD_TYPE= -DTV_BUILD_USING_GPM=OFF -DTV_BUILD_EXAMPLES=OFF -DTV_BUILD_TESTS=ON -DTV_LIBRARY_UNITY_BUILD=ON
92+
cmake --build . -j$(nproc)
93+
7194
build-windows-msvc32:
7295
name: Windows (MSVC) (Win32)
7396
runs-on: windows-latest

examples/tvdemo/ascii.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ void TReport::handleEvent(TEvent& event)
226226
{
227227
if (event.message.command == cmAsciiTableCmdBase + cmCharFocused)
228228
{
229-
asciiChar = event.message.infoByte;
229+
asciiChar = (uchar)(size_t)event.message.infoPtr;
230230
drawView();
231231
}
232232
}

examples/tvdemo/tvdemo3.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ void TVDemo::mouse()
4848

4949
if (mouseCage != 0)
5050
{
51+
int32_t mouseReverse = TEventQueue::mouseReverse;
5152
mouseCage->helpCtx = hcOMMouseDBox;
52-
mouseCage->setData(&(TEventQueue::mouseReverse));
53+
mouseCage->setData(&mouseReverse);
5354
if (deskTop->execView(mouseCage) != cmCancel)
54-
mouseCage->getData(&(TEventQueue::mouseReverse));
55+
mouseCage->getData(&mouseReverse);
56+
TEventQueue::mouseReverse = mouseReverse;
5557
}
5658
destroy( mouseCage );
5759

include/tvision/colors.h

+22
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,34 @@ inline TColorAttr reverseAttribute(TColorAttr attr)
5757
struct TColorRGB
5858
{
5959
uint32_t
60+
#ifndef TV_BIG_ENDIAN
6061
b : 8,
6162
g : 8,
6263
r : 8,
6364
_unused : 8;
65+
#else
66+
_unused : 8,
67+
r : 8,
68+
g : 8,
69+
b : 8;
70+
#endif
6471

6572
TV_TRIVIALLY_CONVERTIBLE(TColorRGB, uint32_t, 0xFFFFFF)
6673
constexpr inline TColorRGB(uint8_t r, uint8_t g, uint8_t b);
6774
};
6875

6976
constexpr inline TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) :
77+
#ifndef TV_BIG_ENDIAN
7078
b(b),
7179
g(g),
7280
r(r),
7381
_unused(0)
82+
#else
83+
_unused(0),
84+
r(r),
85+
g(g),
86+
b(b)
87+
#endif
7488
{
7589
}
7690

@@ -90,11 +104,19 @@ constexpr inline TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) :
90104
struct TColorBIOS
91105
{
92106
uint8_t
107+
#ifndef TV_BIG_ENDIAN
93108
b : 1,
94109
g : 1,
95110
r : 1,
96111
bright : 1,
97112
_unused : 4;
113+
#else
114+
_unused : 4,
115+
bright : 1,
116+
r : 1,
117+
g : 1,
118+
b : 1;
119+
#endif
98120

99121
TV_TRIVIALLY_CONVERTIBLE(TColorBIOS, uint8_t, 0xF)
100122
};

include/tvision/internal/ansidisp.h

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <tvision/tv.h>
66

77
#include <internal/termdisp.h>
8+
#include <internal/endian.h>
89

910
namespace tvision
1011
{
@@ -30,6 +31,9 @@ struct TermColor
3031

3132
TermColor& operator=(uint32_t val) noexcept
3233
{
34+
#ifdef TV_BIG_ENDIAN
35+
reverseBytes(val);
36+
#endif
3337
memcpy(this, &val, sizeof(*this));
3438
return *this;
3539
static_assert(sizeof(*this) == 4, "");
@@ -38,6 +42,9 @@ struct TermColor
3842
{
3943
uint32_t val;
4044
memcpy(&val, this, sizeof(*this));
45+
#ifdef TV_BIG_ENDIAN
46+
reverseBytes(val);
47+
#endif
4148
return val;
4249
}
4350
TermColor(uint8_t aIdx, TermColorTypes aType) noexcept

include/tvision/internal/endian.h

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef TVISION_ENDIAN_H
2+
#define TVISION_ENDIAN_H
3+
4+
#include <stdint.h>
5+
6+
namespace tvision
7+
{
8+
9+
inline void reverseBytes(uint16_t &val)
10+
{
11+
val = (val << 8) | (val >> 8);
12+
}
13+
14+
inline void reverseBytes(uint32_t &val)
15+
{
16+
val = ((val << 8) & 0xFF00FF00U) | ((val >> 8) & 0x00FF00FF);
17+
val = (val << 16) | (val >> 16);
18+
}
19+
20+
inline void reverseBytes(uint64_t &val)
21+
{
22+
val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL);
23+
val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL);
24+
val = (val << 32) | (val >> 32);
25+
}
26+
27+
} // namespace tvision
28+
29+
#endif // TVISION_ENDIAN_H

include/tvision/internal/strings.h

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
#ifndef TVISION_STRINGS_H
22
#define TVISION_STRINGS_H
33

4-
#ifndef _TV_VERSION
54
#include <tvision/tv.h>
6-
#endif
75

86
namespace tvision
97
{
108

119
template<class Int>
1210
inline constexpr Int string_as_int(TStringView s) noexcept
11+
// CAUTION: It is not endian-safe to reinterpret the result as an array of bytes.
1312
{
1413
Int res = 0;
1514
for (size_t i = 0; i < min(s.size(), sizeof(res)); ++i)
16-
// CAUTION: Assumes Little Endian.
1715
res |= uint64_t(uint8_t(s[i])) << 8*i;
1816
return res;
1917
}
@@ -32,15 +30,15 @@ struct alignas(4) btoa_lut_elem_t
3230
using btoa_lut_t = constarray<btoa_lut_elem_t, 256>;
3331

3432
inline char *fast_btoa(uint8_t value, char *buffer) noexcept
33+
// Pre: the capacity of 'buffer' is at least 4 bytes.
3534
{
3635
extern const btoa_lut_t btoa_lut;
3736
const auto &lut = (btoa_lut_elem_t (&) [256]) btoa_lut;
38-
// CAUTION: Assumes Little Endian.
39-
// We can afford to write more bytes into 'buffer' than digits.
40-
uint32_t asInt;
41-
memcpy(&asInt, &lut[value], 4);
42-
memcpy(buffer, &asInt, 4);
43-
return buffer + (asInt >> 24);
37+
// Optimization: read and write the whole LUT entry at once in order to
38+
// minimize memory accesses. We can afford to write more bytes into 'buffer'
39+
// than digits.
40+
memcpy(buffer, &lut[value], 4);
41+
return buffer + (uint8_t) buffer[3];
4442
static_assert(sizeof(btoa_lut_elem_t) == 4, "");
4543
}
4644

include/tvision/internal/utf8.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#ifndef TVISION_UTF8_H
22
#define TVISION_UTF8_H
33

4-
#include <internal/strings.h>
4+
#include <tvision/tv.h>
5+
6+
#include <internal/endian.h>
57

68
#include <stdint.h>
79
#include <string.h>
@@ -66,6 +68,9 @@ inline size_t utf32To8(uint32_t u32, char u8[4]) noexcept
6668
(( u32 & 0b00111111) | 0b10000000) << 24;
6769
length = 4;
6870
}
71+
#ifdef TV_BIG_ENDIAN
72+
reverseBytes(asInt);
73+
#endif
6974
memcpy(u8, &asInt, 4);
7075
return length;
7176
}

include/tvision/scrncell.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ struct TCellChar
7676

7777
inline void TCellChar::moveChar(char ch)
7878
{
79-
moveInt((uchar) ch);
79+
memset(this, 0, sizeof(*this));
80+
_text[0] = ch;
8081
}
8182

8283
inline void TCellChar::moveInt(uint32_t mbc, bool wide)
84+
// Pre: 'mbc' is a bit-casted multibyte-encoded character.
8385
{
8486
memset(this, 0, sizeof(*this));
85-
// CAUTION: Assumes Little Endian.
8687
memcpy(_text, &mbc, sizeof(mbc));
8788
_flags = -int(wide) & fWide;
8889
}

include/tvision/system.h

+5
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,13 @@ inline void TMouse::registerHandler( unsigned mask, void (_FAR *func)() )
187187

188188
struct CharScanType
189189
{
190+
#if !defined( TV_BIG_ENDIAN )
190191
uchar charCode;
191192
uchar scanCode;
193+
#else
194+
uchar scanCode;
195+
uchar charCode;
196+
#endif
192197
};
193198

194199
struct KeyDownEvent

source/CMakeLists.txt

+11
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
7474
TVISION_NO_STL
7575
)
7676

77+
include(TestBigEndian)
78+
79+
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
80+
81+
if (IS_BIG_ENDIAN)
82+
tv_message(STATUS "Big endian system detected")
83+
target_compile_definitions(${PROJECT_NAME} PUBLIC
84+
TV_BIG_ENDIAN
85+
)
86+
endif()
87+
7788
# Dependencies
7889

7990
if (NOT WIN32)

source/platform/ansidisp.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,13 @@ struct alignas(8) colorconv_r
156156
uint8_t unused[2];
157157

158158
colorconv_r() = default;
159-
colorconv_r(TermColor aColor, TColorAttr::Style aExtraFlags=0) noexcept
159+
colorconv_r(TermColor aColor, TColorAttr::Style aExtraFlags = 0) noexcept
160160
{
161+
// Optimization: do bit-casting manually, just like with TermColor.
161162
uint64_t val = aColor | (uint64_t(aExtraFlags) << 32);
163+
#ifdef TV_BIG_ENDIAN
164+
reverseBytes(val);
165+
#endif
162166
memcpy(this, &val, 8);
163167
static_assert(sizeof(*this) == 8, "");
164168
}

source/platform/buffdisp.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ inline void FlushScreenAlgorithm::writeCell() noexcept
340340
inline void FlushScreenAlgorithm::writeSpace() noexcept
341341
{
342342
TCellChar ch;
343-
ch.moveInt(' ');
343+
ch.moveChar(' ');
344344
writeCell(ch, cell->attr, 0);
345345
}
346346

source/platform/far2l.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <internal/constmap.h>
77
#include <internal/base64.h>
88
#include <internal/events.h>
9+
#include <internal/endian.h>
910

1011
#include <time.h>
1112

@@ -97,6 +98,16 @@ ParseResult parseFar2lInput(GetChBuf &buf, TEvent &ev, InputState &state) noexce
9798
memcpy(&kev.dwControlKeyState, &out[6], 4);
9899
memcpy(&kev.uChar.UnicodeChar, &out[10], 4);
99100

101+
#ifdef TV_BIG_ENDIAN
102+
// The protocol states that "all integer values are in
103+
// little-endian format", so convert them.
104+
reverseBytes(kev.wRepeatCount);
105+
reverseBytes(kev.wVirtualKeyCode);
106+
reverseBytes(kev.wVirtualScanCode);
107+
reverseBytes(kev.dwControlKeyState);
108+
reverseBytes((uint32_t &) kev.uChar.UnicodeChar);
109+
#endif
110+
100111
if (uint16_t keyCode = virtualKeyCodeToKeyCode[kev.wVirtualKeyCode])
101112
{
102113
kev.wVirtualScanCode = keyCode >> 8;
@@ -120,6 +131,14 @@ ParseResult parseFar2lInput(GetChBuf &buf, TEvent &ev, InputState &state) noexce
120131
memcpy(&mev.dwControlKeyState, &out[8], 4);
121132
memcpy(&mev.dwEventFlags, &out[12], 4);
122133

134+
#ifdef TV_BIG_ENDIAN
135+
reverseBytes((uint16_t &) mev.dwMousePosition.X);
136+
reverseBytes((uint16_t &) mev.dwMousePosition.Y);
137+
reverseBytes(mev.dwButtonState);
138+
reverseBytes(mev.dwControlKeyState);
139+
reverseBytes(mev.dwEventFlags);
140+
#endif
141+
123142
getWin32Mouse(mev, ev, state);
124143
return Accepted;
125144
}

source/platform/win32con.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ bool getWin32Key(const KEY_EVENT_RECORD &KeyEvent, TEvent &ev, InputState &state
413413

414414
ev.what = evKeyDown;
415415
ev.keyDown.charScan.scanCode = KeyEvent.wVirtualScanCode;
416-
ev.keyDown.charScan.charCode = KeyEvent.uChar.AsciiChar;
416+
ev.keyDown.charScan.charCode = (uchar) KeyEvent.uChar.UnicodeChar;
417417
ev.keyDown.controlKeyState = KeyEvent.dwControlKeyState & (
418418
kbShift | kbCtrlShift | kbAltShift |
419419
kbScrollState | kbNumState | kbCapsState | kbEnhanced

0 commit comments

Comments
 (0)