///|
let default_extra_characters : String = "äöüÄÖÜß»«ëïÿËÏáéíóúýÁÉÍÓÚÝàèìòùÀÈÌÒÙâêîôûÂÊÎÔÛåÅøØãñõÃÑÕæÆçÇþðÞУœŒ¡¿"
///|
fn Machine::extra_character_table(self : Machine) -> (Int32, Int32) raise Fault {
let extension = if self.version == 5 { self.word(54) } else { 0 }
let table = if extension != 0 && self.word(extension) >= 3 {
self.word(extension + 6)
} else {
0
}
let count = if table == 0 {
default_extra_characters.length()
} else {
self.byte(table)
}
if count > 97 {
raise Invalid("Unicode translation table exceeds 97 characters")
}
(table, count)
}
///|
fn Machine::extra_character(
self : Machine,
table : Int32,
index : Int32,
) -> Int32 raise Fault {
let code = if table == 0 {
default_extra_characters[index].to_int()
} else {
self.word(table + 1 + 2 * index)
}
if code >= 0xd800 && code <= 0xdfff {
raise Invalid("surrogate Unicode character")
}
code
}
///|
fn Machine::unicode_zscii(self : Machine, code : Int32) -> Int32 raise Fault {
if code >= 32 && code <= 126 {
return code
}
if code == 10 || code == 13 {
return 13
}
if code == 0 {
return 0
}
let (table, count) = self.extra_character_table()
for i in 0.. Unit raise Fault {
if code >= 0xd800 && code <= 0xdfff {
raise Invalid("surrogate Unicode character")
}
if !self.streams.is_empty() {
self.emit(self.unicode_zscii(code))
} else if self.screen {
self.display_char(code)
}
}
///|
fn Machine::emit(self : Machine, code : Int32) -> Unit raise Fault {
if code == 0 {
return
}
if !self.streams.is_empty() {
let table = self.streams[self.streams.length() - 1]
let n = self.word(table)
self.put_byte(table + 2 + n, code)
self.put_word(table, n + 1)
} else if self.screen {
if code == 13 {
self.display_char(10)
} else if code >= 32 && code <= 126 {
self.display_char(code)
} else if code >= 155 && code <= 251 {
let (table, count) = self.extra_character_table()
if code - 155 >= count {
raise Invalid("undefined ZSCII character")
}
self.display_char(self.extra_character(table, code - 155))
} else {
raise Invalid("unsupported ZSCII output code \{code}")
}
}
}
///|
fn Machine::print_text(
self : Machine,
addr : Int32,
depth~ : Int32 = 0,
) -> Int32 raise Fault {
if depth > 16 {
raise Invalid("recursive abbreviation")
}
let zchars : Array[Int32] = []
let mut p = addr
while true {
let w = self.word(p)
p += 2
zchars.push((w >> 10) & 31)
zchars.push((w >> 5) & 31)
zchars.push(w & 31)
if (w & 32768) != 0 {
break
}
}
let mut alphabet = 0
let mut i = 0
while i < zchars.length() {
let z = zchars[i]
i += 1
if z == 0 {
self.emit(32)
alphabet = 0
} else if z >= 1 && z <= 3 {
if depth != 0 {
raise Invalid("abbreviation nested inside abbreviation")
}
if i >= zchars.length() {
raise Invalid("truncated abbreviation")
}
let index = 32 * (z - 1) + zchars[i]
i += 1
let _ = self.print_text(
self.word(self.abbreviations + 2 * index) * 2,
depth=depth + 1,
)
alphabet = 0
} else if z == 4 {
alphabet = 1
} else if z == 5 {
alphabet = 2
} else if alphabet == 2 && z == 6 {
if i + 1 >= zchars.length() {
raise Invalid("truncated ZSCII escape")
}
self.emit(zchars[i] * 32 + zchars[i + 1])
i += 2
alphabet = 0
} else {
let custom = if self.version == 5 { self.word(52) } else { 0 }
let code = if custom != 0 {
self.byte(custom + alphabet * 26 + z - 6)
} else if alphabet == 0 {
97 + z - 6
} else if alphabet == 1 {
65 + z - 6
} else if z == 7 {
13
} else {
let punctuation = "0123456789.,!?_#'\"/\\-:()"
punctuation[z - 8].to_int()
}
self.emit(code)
alphabet = 0
}
}
p
}