QR weergeven op IBM 3151
Voor revbank hebben we een mooie antieke terminal staan, en Xesxen van Hackalot heeft een plugin gemaakt die bij een deposit een QR-code kan weergeven. Echter, die QR gebruikt UTF-8 en de terminal is een paar jaaar ouder dan UTF-8.
█████████████████████████ ██ ▄▄▄▄▄ █▀ █ ▄█ ▄▄▄▄▄ ██ ██ █ █ █▄ █▀▄█ █ █ ██ ██ █▄▄▄█ █ ██▀ █ █▄▄▄█ ██ ██▄▄▄▄▄▄▄█ ▀ ▀ █▄▄▄▄▄▄▄██ ██▄ █▄██▄ █▄ ███ █ ▀██ ██▀ ▀ █▄▄▀█▀▄▀▄▄ ▄█ █▀▄██ ██▄███▄▄▄▄ █ ▀▄▀█ ▄█▀ ██ ██ ▄▄▄▄▄ █▄▀ ▀▀██▄▄██▄▀██ ██ █ █ █▀ █▄█ █ ▀▄█ ▀██ ██ █▄▄▄█ █▀█▀█▄▀█ ▄███▄██ ██▄▄▄▄▄▄▄█▄███▄█▄█▄▄█▄███ █████████████████████████
(Bovenstaande zal door menig scanner niet herkend worden omdat het gemaakt is voor witte tekens op een zwarte achtergrond, en deze pagina's het andersom hebben.)
ROM-kaart
In de terminal zat een ROM-kaart, en die heeft de juiste tekens niet in de tekenset. Door de kaart uit de terminal te halen, laadt ie z'n ingebouwde ROM. Die heeft geen tekens met accenten, maar weer wel de blokjes.
Ingebouwde ROM
De speciale tekens in G1 zijn makkelijk te benaderen als je 8 bit communicatie aan hebt staan: 0x80 | char.
Behalve spatie zijn de volgende tekens nodig voor een qrcode zoals gemaakt met qrencode -t utf8:
Teken | Codepoint | Teken in G1 | 8 bit |
---|---|---|---|
▀ | U+2580: UPPER HALF BLOCK | 0x73 | 0xf3 |
▄ | U+2584: LOWER HALF BLOCK | 0x72 | 0xf2 |
█ | U+2588: FULL BLOCK | 0x7e | 0xfe |
GNU Screen
In principe gaat line drawing prima omdat applicaties die meestal niet zomaar als UTF-8 uitvoeren, maar opzoeken hoe de terminal het wil hebben. Termcap/terminfo helpt in dit geval echter niet, want die heeft wel definities voor line drawing characters, maar niet voor block drawing.
Screen kan wel vertalen van UTF-8 naar de encoding van de terminal. Het heeft echter een hard coded lijst ondersteunde encodings, dus om een extra encoding toevoegen zou je opnieuw moeten compilen, bah. Daarom heb ik een bestaande encoding gekaapt. Kan best, want in de praktijk gebruikt iedereen verder toch wel UTF-8.
Er is een ongedocumenteerde feature om zelf zo'n vertaalbestand te kunnen laden: :encoding -l /pad/naar/bestandje. Dan heb je geen root access nodig om een bestand in /usr/share/screen/utf8encodings te overschrijven en hebben andere gebruikers er geen last van.
Het bestandsformaat is als volgt: er is een magic van 12 bytes, ScreenI2UTF8 aan het begin, gevolgd door een byte die de versie van het bestand aangeeft. De enige versie is 0. Dan een byte die moet overeenkomen met de numerieke waarde die hardcoded in encoding.c staat. Voor ISO8859-15 is het 0x80|'b' oftewel 0xe2. Vervolgens 16 bits die de lengte van de *rest* van het bestand aangeeft. In die rest komt eerst de naam van het ding, \0 terminated en gepad naar een veelvoud van 2 bytes. Tot slot komt de daadwerkelijke tabel: steeds een paar van twee 16 bit waarden. De eerste waarde is het codepoint in de tabel die je definieert, het tweede het corresponderende codepoint in UTF-8.
Ik heb als basis /usr/share/screen/utf8encodings/e2 genomen, die hoort bij de ingebouwde encoding ISO8859-15 (let op: screen wil geen streepje na ISO!), en de eerste paar tekens overschreven. De rest heb ik laten staan, en klopt dus niet echt voor onze usecase.
In theorie zou screen de encoding uit de locale moeten halen, maar /etc/locale.gen, locale-gen, en export LANG=en_US.ISO-8859-1 haalde niks uit. Je kan 't ook instellen met de 2e parameter van screen's :encoding.
In .screenrc wordt via de ongedocumenteerde feature het bestand, dat ik .screen.e2 heb genoemd, geladen:
encoding -l /home/bar/.screen.e2 encoding UTF-8 ISO8859-15 utf8 on
Het werkt!