Created
August 3, 2023 22:37
-
-
Save twobob/b13d7db0d5c05329941f5b3f216d7e33 to your computer and use it in GitHub Desktop.
# PETSCII to UTF-8 conversion functions and tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# PETSCII to UTF-8 conversion functions and tests | |
import unittest | |
def prtchflush(c: int) -> str: | |
# ISO8859-15 to UTF-8 | |
special_characters = { | |
0xA4: 0x20AC, # € | |
0xA6: 0x160, # Š | |
0xA8: 0x161, # š | |
0xB4: 0x17D, # Ž | |
0xB8: 0x17E, # ž | |
0xBC: 0x152, # Œ | |
0xBD: 0x153, # œ | |
0xBE: 0x178, # Ÿ | |
} | |
if c in special_characters: | |
return prtuptflush(special_characters[c]) | |
else: | |
if c < 0x80: | |
return chr(c) | |
else: | |
first_byte = 0xC2 + (c > 0xBF) | |
second_byte = (c & 0x3F) + 0x80 | |
return chr(first_byte) + chr(second_byte) | |
def prtuptflush(utf: int) -> str: | |
return chr(utf) | |
def prtnumflush(fmt: str, *values) -> str: | |
return fmt % values | |
class EchoCharState: | |
def __init__(self): | |
self.shifted = False | |
self.color = 97 | |
self.backcolor = 44 | |
def echochar(c: int, shifted: int = 0) -> str: | |
output = "" | |
if 0x00 <= c <= 0x1F: | |
if c == 0x0D: | |
output += prtuptflush(0x24B9) + "\\n" | |
elif c == 0x0A: | |
output += prtuptflush(0x24B6) | |
else: | |
output += prtuptflush(0x2400 + c) | |
elif 0x20 <= c <= 0x3F: | |
output += chr(c) | |
elif 0x40 <= c <= 0x5F: | |
output += chr(c) | |
elif 0x60 <= c <= 0x7A: | |
output += prtchflush(c - 0x61 + ord('A')) if c != 0x60 else '`' | |
elif 0x80 <= c <= 0x9F: | |
if c == 0x8D: | |
output += prtuptflush(0x24B9) + "\\n" | |
else: | |
output += prtuptflush(0x2400 + (c - 0x80)) | |
elif 0xA0 <= c <= 0xBF: | |
if c == 0xA0: | |
output += ' ' | |
elif c == 0xAD: | |
output += prtuptflush(0x24B9) + "\\n" | |
else: | |
output += prtuptflush(0x2400 + (c - 0x80)) | |
elif 0xC1 <= c <= 0xDA: | |
output += prtchflush(shifted + c - 0xC1 + ord('A')) | |
elif c == 0xE0: | |
output += '£' # Pound symbol | |
else: | |
output += chr(c) # Other special characters | |
return output | |
class TestEchochar(unittest.TestCase): | |
def test_control_characters(self): | |
self.assertEqual(echochar(0x0D), 'Ⓓ\\n') | |
self.assertEqual(echochar(0x0A), 'Ⓐ') | |
self.assertEqual(echochar(0x00), '␀') | |
self.assertEqual(echochar(0x1F), '␟') | |
def test_graphical_symbols(self): | |
self.assertEqual(echochar(0x20), ' ') | |
self.assertEqual(echochar(0x21), '!') | |
self.assertEqual(echochar(0x40), '@') | |
self.assertEqual(echochar(0x5F), '_') | |
def test_lower_case_letters(self): | |
self.assertEqual(echochar(0x60), '`') | |
self.assertEqual(echochar(0x61), 'A') # Corrected test for character 0x61 | |
self.assertEqual(echochar(0x7A), 'Z') | |
self.assertEqual(echochar(0x7F), '') | |
def test_more_control_characters(self): | |
self.assertEqual(echochar(0x8D), 'Ⓓ\\n') | |
self.assertEqual(echochar(0x80), '␀') | |
self.assertEqual(echochar(0x9F), '␟') | |
def test_upper_case_letters(self): | |
self.assertEqual(echochar(0xC1), 'A') # Uppercase 'A' | |
self.assertEqual(echochar(0xDA), 'Z') # Uppercase 'Z' | |
self.assertEqual(echochar(0xE0), '£') # Pound symbol | |
self.assertEqual(echochar(0xFF), 'ÿ') # Corrected character | |
class TestEchocharAdditional(unittest.TestCase): | |
def test_control_characters(self): | |
self.assertEqual(echochar(0x0D), 'Ⓓ\\n') | |
self.assertEqual(echochar(0x0A), 'Ⓐ') | |
self.assertEqual(echochar(0x00), '␀') | |
self.assertEqual(echochar(0x1F), '␟') | |
def test_graphical_symbols(self): | |
self.assertEqual(echochar(0x20), ' ') | |
self.assertEqual(echochar(0x21), '!') | |
self.assertEqual(echochar(0x40), '@') | |
self.assertEqual(echochar(0x5F), '_') | |
def test_lower_case_letters(self): | |
self.assertEqual(echochar(0x60), '`') | |
self.assertEqual(echochar(0x61), 'A') # Corrected test for character 0x61 | |
self.assertEqual(echochar(0x7A), 'Z') | |
self.assertEqual(echochar(0x7F), '') | |
def test_more_control_characters(self): | |
self.assertEqual(echochar(0x8D), 'Ⓓ\\n') | |
self.assertEqual(echochar(0x80), '␀') | |
self.assertEqual(echochar(0x9F), '␟') | |
def test_upper_case_letters(self): | |
self.assertEqual(echochar(0xC1), 'A') # Uppercase 'A' | |
self.assertEqual(echochar(0xDA), 'Z') # Uppercase 'Z' | |
self.assertEqual(echochar(0xE0), '£') # Pound symbol | |
self.assertEqual(echochar(0xFF), 'ÿ') # Corrected character | |
def echochar_with_state(c: int, state: EchoCharState) -> (EchoCharState, str): | |
output = "" | |
if (0x00 <= c <= 0x1F) or (0x80 <= c <= 0x9F): | |
if c == 0x1B: # Escape sequence handling for 0x1B | |
output += "\e" # Escape character, not part of PETSCII, but useful in VT100 | |
elif c == 0x01: # Swap colors | |
tempcolor = state.color | |
state.color = (30 if state.backcolor < 100 else 90) + state.backcolor % 10 | |
state.backcolor = (40 if tempcolor < 100 else 100) + tempcolor % 10 | |
output += prtnumflush("\e[%d;%dm", state.color, state.backcolor) | |
elif c == 0x05: | |
output += prtnumflush("\e[%dm", 97) | |
state.color = 97 | |
elif c == 0x0A: | |
output += prtuptflush(0x24B6) | |
output += "\\n" | |
elif c == 0x0D: | |
output += prtuptflush(0x24B9) | |
output += "\\n" | |
elif c == 0x8D: | |
output += prtuptflush(0x24CB) | |
output += "\\n" | |
elif c == 0x02: # Toggle shifted mode | |
state.shifted = not state.shifted | |
elif c == 0x03: # Clear color attributes | |
state.color = 97 | |
state.backcolor = 44 | |
elif c == 0x04: # Clear screen | |
output += "\e[2J" | |
elif c == 0x06: # Shifted mode off | |
state.shifted = False | |
elif c == 0x07: # Beep | |
output += "\a" | |
elif c == 0x08: # Backspace | |
output += "\b" | |
elif c == 0x09: # Tab | |
output += "\t" | |
elif c == 0x0E: # Clear to end of line | |
output += "\e[K" | |
elif c == 0x11: # Cursor down | |
output += "\e[B" | |
elif c == 0x12: # Reverse on | |
output += "\e[7m" | |
elif c == 0x13: # Reverse off | |
output += "\e[27m" | |
elif c == 0x14: # Cursor up | |
output += "\e[A" | |
elif c == 0x15: # Cursor right | |
output += "\e[C" | |
elif c == 0x16: # Cursor left | |
output += "\e[D" | |
else: | |
output += echochar(c, state.shifted) # Existing echochar function | |
return state, output | |
class TestEchocharWithState(unittest.TestCase): | |
def test_swap_colors(self): | |
state = EchoCharState() | |
new_state, output = echochar_with_state(0x01, state) | |
self.assertEqual(output, "\e[34;47m") | |
class TestEchocharWithStateAdditionalControls(unittest.TestCase): | |
def test_swap_colors(self): | |
state = EchoCharState() | |
state.color = 97 # Initial color | |
state.backcolor = 44 # Initial backcolor | |
new_state, output = echochar_with_state(0x01, state) | |
self.assertEqual(output, "\e[34;47m") | |
self.assertEqual(new_state.color, 34) | |
self.assertEqual(new_state.backcolor, 47) | |
def test_toggle_shifted_mode(self): | |
state = EchoCharState() | |
new_state, _ = echochar_with_state(0x02, state) | |
self.assertTrue(new_state.shifted) | |
new_state, _ = echochar_with_state(0x02, new_state) | |
self.assertFalse(new_state.shifted) | |
def test_clear_color_attributes(self): | |
state = EchoCharState() | |
new_state, _ = echochar_with_state(0x03, state) | |
self.assertEqual(new_state.color, 97) | |
self.assertEqual(new_state.backcolor, 44) | |
def test_clear_screen(self): | |
_, output = echochar_with_state(0x04, EchoCharState()) | |
self.assertEqual(output, "\e[2J") | |
def test_shifted_mode_off(self): | |
state = EchoCharState() | |
state.shifted = True | |
new_state, _ = echochar_with_state(0x06, state) | |
self.assertFalse(new_state.shifted) | |
def test_beep(self): | |
_, output = echochar_with_state(0x07, EchoCharState()) | |
self.assertEqual(output, "\a") | |
def test_backspace(self): | |
_, output = echochar_with_state(0x08, EchoCharState()) | |
self.assertEqual(output, "\b") | |
def test_tab(self): | |
_, output = echochar_with_state(0x09, EchoCharState()) | |
self.assertEqual(output, "\t") | |
# Unit test for the prtchflush function | |
class TestPrtchflush(unittest.TestCase): | |
def test_iso8859_15_to_utf8_conversion(self): | |
self.assertEqual(prtchflush(0xA4), '€') | |
self.assertEqual(prtchflush(0xA6), 'Š') | |
self.assertEqual(prtchflush(0xA8), 'š') | |
self.assertEqual(prtchflush(0xB4), 'Ž') | |
self.assertEqual(prtchflush(0xB8), 'ž') | |
self.assertEqual(prtchflush(0xBC), 'Œ') | |
self.assertEqual(prtchflush(0xBD), 'œ') | |
self.assertEqual(prtchflush(0xBE), 'Ÿ') | |
self.assertEqual(prtchflush(0x41), 'A') # Regular ASCII character | |
if __name__ == '__main__': | |
unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment