Skip to content

Instantly share code, notes, and snippets.

@twobob
Created August 3, 2023 22:37
Show Gist options
  • Save twobob/b13d7db0d5c05329941f5b3f216d7e33 to your computer and use it in GitHub Desktop.
Save twobob/b13d7db0d5c05329941f5b3f216d7e33 to your computer and use it in GitHub Desktop.
# PETSCII to UTF-8 conversion functions and tests
# 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