llvm-mos-sdk
charset.h
Go to the documentation of this file.
1 // Copyright 2023 LLVM-MOS Project Licensed under the Apache License,
2 // Version 2.0 with LLVM Exceptions. See
3 // https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license
4 // information.
5 
6 #if __cplusplus < 202002L
7 #error charset support requies C++20
8 #else
9 #ifndef _CHARSET_H
10 #define _CHARSET_H
11 
12 #include <cstddef>
13 
14 namespace charset_impl {
15 
16 template <size_t N> struct UnshiftedString {
17  char Str[N]{};
18 
19  constexpr UnshiftedString(char const (&Src)[N]) {
20  for (size_t I = 0; I < N; ++I) {
21  if (Src[I] >= 0x80)
22  throw "use U prefix for unicode string literals";
23  Str[I] = TranslateUnicode(Src[I]);
24  }
25  }
26 
27  constexpr UnshiftedString(char16_t const (&Src)[N]) {
28  for (size_t I = 0; I < N; ++I) {
29  if (Src[I] >= 0xD800 && Src[I] <= 0xDFFF)
30  throw "use U prefix for unicode string literals";
31  Str[I] = TranslateUnicode(Src[I]);
32  }
33  }
34 
35  constexpr UnshiftedString(char32_t const (&Src)[N]) {
36  for (size_t I = 0; I < N; ++I)
37  Str[I] = TranslateUnicode(Src[I]);
38  }
39 
40  constexpr char TranslateUnicode(char32_t C) {
41  switch (C) {
42  default:
43  throw "Unsupported";
44 
45  // C0 control codes are uninterpreted.
46  case 0x0000 ... 0x001f:
47  return C;
48 
49  // Name: Map from Commodore PET (interchange) primary character set to
50  // Unicode
51 
52  // Date: 2018 April 20
53 
54  // Author: Rebecca Bettencourt <support@kreativekorp.com>
55 
56  case 0x0020:
57  return 0x20; // SPACE
58  case 0x0021:
59  return 0x21; // EXCLAMATION MARK
60  case 0x0022:
61  return 0x22; // QUOTATION MARK
62  case 0x0023:
63  return 0x23; // NUMBER SIGN
64  case 0x0024:
65  return 0x24; // DOLLAR SIGN
66  case 0x0025:
67  return 0x25; // PERCENT SIGN
68  case 0x0026:
69  return 0x26; // AMPERSAND
70  case 0x0027:
71  return 0x27; // APOSTROPHE
72  case 0x0028:
73  return 0x28; // LEFT PARENTHESIS
74  case 0x0029:
75  return 0x29; // RIGHT PARENTHESIS
76  case 0x002A:
77  return 0x2A; // ASTERISK
78  case 0x002B:
79  return 0x2B; // PLUS SIGN
80  case 0x002C:
81  return 0x2C; // COMMA
82  case 0x002D:
83  return 0x2D; // HYPHEN-MINUS
84  case 0x002E:
85  return 0x2E; // FULL STOP
86  case 0x002F:
87  return 0x2F; // SOLIDUS
88  case 0x0030:
89  return 0x30; // DIGIT ZERO
90  case 0x0031:
91  return 0x31; // DIGIT ONE
92  case 0x0032:
93  return 0x32; // DIGIT TWO
94  case 0x0033:
95  return 0x33; // DIGIT THREE
96  case 0x0034:
97  return 0x34; // DIGIT FOUR
98  case 0x0035:
99  return 0x35; // DIGIT FIVE
100  case 0x0036:
101  return 0x36; // DIGIT SIX
102  case 0x0037:
103  return 0x37; // DIGIT SEVEN
104  case 0x0038:
105  return 0x38; // DIGIT EIGHT
106  case 0x0039:
107  return 0x39; // DIGIT NINE
108  case 0x003A:
109  return 0x3A; // COLON
110  case 0x003B:
111  return 0x3B; // SEMICOLON
112  case 0x003C:
113  return 0x3C; // LESS-THAN SIGN
114  case 0x003D:
115  return 0x3D; // EQUALS SIGN
116  case 0x003E:
117  return 0x3E; // GREATER-THAN SIGN
118  case 0x003F:
119  return 0x3F; // QUESTION MARK
120  case 0x0040:
121  return 0x40; // COMMERCIAL AT
122  case 0x0041:
123  return 0x41; // LATIN CAPITAL LETTER A
124  case 0x0042:
125  return 0x42; // LATIN CAPITAL LETTER B
126  case 0x0043:
127  return 0x43; // LATIN CAPITAL LETTER C
128  case 0x0044:
129  return 0x44; // LATIN CAPITAL LETTER D
130  case 0x0045:
131  return 0x45; // LATIN CAPITAL LETTER E
132  case 0x0046:
133  return 0x46; // LATIN CAPITAL LETTER F
134  case 0x0047:
135  return 0x47; // LATIN CAPITAL LETTER G
136  case 0x0048:
137  return 0x48; // LATIN CAPITAL LETTER H
138  case 0x0049:
139  return 0x49; // LATIN CAPITAL LETTER I
140  case 0x004A:
141  return 0x4A; // LATIN CAPITAL LETTER J
142  case 0x004B:
143  return 0x4B; // LATIN CAPITAL LETTER K
144  case 0x004C:
145  return 0x4C; // LATIN CAPITAL LETTER L
146  case 0x004D:
147  return 0x4D; // LATIN CAPITAL LETTER M
148  case 0x004E:
149  return 0x4E; // LATIN CAPITAL LETTER N
150  case 0x004F:
151  return 0x4F; // LATIN CAPITAL LETTER O
152  case 0x0050:
153  return 0x50; // LATIN CAPITAL LETTER P
154  case 0x0051:
155  return 0x51; // LATIN CAPITAL LETTER Q
156  case 0x0052:
157  return 0x52; // LATIN CAPITAL LETTER R
158  case 0x0053:
159  return 0x53; // LATIN CAPITAL LETTER S
160  case 0x0054:
161  return 0x54; // LATIN CAPITAL LETTER T
162  case 0x0055:
163  return 0x55; // LATIN CAPITAL LETTER U
164  case 0x0056:
165  return 0x56; // LATIN CAPITAL LETTER V
166  case 0x0057:
167  return 0x57; // LATIN CAPITAL LETTER W
168  case 0x0058:
169  return 0x58; // LATIN CAPITAL LETTER X
170  case 0x0059:
171  return 0x59; // LATIN CAPITAL LETTER Y
172  case 0x005A:
173  return 0x5A; // LATIN CAPITAL LETTER Z
174  case 0x005B:
175  return 0x5B; // LEFT SQUARE BRACKET
176  case 0x005C:
177  return 0x5C; // REVERSE SOLIDUS
178  case 0x005D:
179  return 0x5D; // RIGHT SQUARE BRACKET
180  case 0x2191:
181  return 0x5E; // UPWARDS ARROW
182  case 0x2190:
183  return 0x5F; // LEFTWARDS ARROW
184  case 0x2500:
185  return 0x60; // BOX DRAWINGS LIGHT HORIZONTAL
186  case 0x2660:
187  return 0x61; // BLACK SPADE SUIT
188  case 0x1FB72:
189  return 0x62; // VERTICAL ONE EIGHTH BLOCK-4
190  case 0x1FB78:
191  return 0x63; // HORIZONTAL ONE EIGHTH BLOCK-4
192  case 0x1FB77:
193  return 0x64; // HORIZONTAL ONE EIGHTH BLOCK-3
194  case 0x1FB76:
195  return 0x65; // HORIZONTAL ONE EIGHTH BLOCK-2
196  case 0x1FB7A:
197  return 0x66; // HORIZONTAL ONE EIGHTH BLOCK-6
198  case 0x1FB71:
199  return 0x67; // VERTICAL ONE EIGHTH BLOCK-3
200  case 0x1FB74:
201  return 0x68; // VERTICAL ONE EIGHTH BLOCK-6
202  case 0x256E:
203  return 0x69; // BOX DRAWINGS LIGHT ARC DOWN AND LEFT
204  case 0x2570:
205  return 0x6A; // BOX DRAWINGS LIGHT ARC UP AND RIGHT
206  case 0x256F:
207  return 0x6B; // BOX DRAWINGS LIGHT ARC UP AND LEFT
208  case 0x1FB7C:
209  return 0x6C; // LEFT AND LOWER ONE EIGHTH BLOCK
210  case 0x2572:
211  return 0x6D; // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
212  case 0x2571:
213  return 0x6E; // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
214  case 0x1FB7D:
215  return 0x6F; // LEFT AND UPPER ONE EIGHTH BLOCK
216  case 0x1FB7E:
217  return 0x70; // RIGHT AND UPPER ONE EIGHTH BLOCK
218  case 0x2022:
219  case 0x25CF:
220  return 0x71; // BULLET (or 0x25CF BLACK CIRCLE)
221  case 0x1FB7B:
222  return 0x72; // HORIZONTAL ONE EIGHTH BLOCK-7
223  case 0x2665:
224  return 0x73; // BLACK HEART SUIT
225  case 0x1FB70:
226  return 0x74; // VERTICAL ONE EIGHTH BLOCK-2
227  case 0x256D:
228  return 0x75; // BOX DRAWINGS LIGHT ARC DOWN AND RIGHT
229  case 0x2573:
230  return 0x76; // BOX DRAWINGS LIGHT DIAGONAL CROSS
231  case 0x25CB:
232  case 0x25E6:
233  return 0x77; // WHITE CIRCLE (or 0x25E6 WHITE BULLET)
234  case 0x2663:
235  return 0x78; // BLACK CLUB SUIT
236  case 0x1FB75:
237  return 0x79; // VERTICAL ONE EIGHTH BLOCK-7
238  case 0x2666:
239  return 0x7A; // BLACK DIAMOND SUIT
240  case 0x253C:
241  return 0x7B; // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
242  case 0x1FB8C:
243  return 0x7C; // LEFT HALF MEDIUM SHADE
244  case 0x2502:
245  return 0x7D; // BOX DRAWINGS LIGHT VERTICAL
246  case 0x03C0:
247  return 0x7E; // GREEK SMALL LETTER PI
248  case 0x25E5:
249  return 0x7F; // BLACK UPPER RIGHT TRIANGLE
250  case 0x00A0:
251  return 0xA0; // NO-BREAK SPACE
252  case 0x258C:
253  return 0xA1; // LEFT HALF BLOCK
254  case 0x2584:
255  return 0xA2; // LOWER HALF BLOCK
256  case 0x2594:
257  return 0xA3; // UPPER ONE EIGHTH BLOCK
258  case 0x2581:
259  return 0xA4; // LOWER ONE EIGHTH BLOCK
260  case 0x258F:
261  return 0xA5; // LEFT ONE EIGHTH BLOCK
262  case 0x2592:
263  return 0xA6; // MEDIUM SHADE
264  case 0x2595:
265  return 0xA7; // RIGHT ONE EIGHTH BLOCK
266  case 0x1FB8F:
267  return 0xA8; // LOWER HALF MEDIUM SHADE
268  case 0x25E4:
269  return 0xA9; // BLACK UPPER LEFT TRIANGLE
270  case 0x1FB87:
271  return 0xAA; // RIGHT ONE QUARTER BLOCK
272  case 0x251C:
273  return 0xAB; // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
274  case 0x2597:
275  return 0xAC; // QUADRANT LOWER RIGHT
276  case 0x2514:
277  return 0xAD; // BOX DRAWINGS LIGHT UP AND RIGHT
278  case 0x2510:
279  return 0xAE; // BOX DRAWINGS LIGHT DOWN AND LEFT
280  case 0x2582:
281  return 0xAF; // LOWER ONE QUARTER BLOCK
282  case 0x250C:
283  return 0xB0; // BOX DRAWINGS LIGHT DOWN AND RIGHT
284  case 0x2534:
285  return 0xB1; // BOX DRAWINGS LIGHT UP AND HORIZONTAL
286  case 0x252C:
287  return 0xB2; // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
288  case 0x2524:
289  return 0xB3; // BOX DRAWINGS LIGHT VERTICAL AND LEFT
290  case 0x258E:
291  return 0xB4; // LEFT ONE QUARTER BLOCK
292  case 0x258D:
293  return 0xB5; // LEFT THREE EIGHTHS BLOCK
294  case 0x1FB88:
295  return 0xB6; // RIGHT THREE EIGHTHS BLOCK
296  case 0x1FB82:
297  return 0xB7; // UPPER ONE QUARTER BLOCK
298  case 0x1FB83:
299  return 0xB8; // UPPER THREE EIGHTHS BLOCK
300  case 0x2583:
301  return 0xB9; // LOWER THREE EIGHTHS BLOCK
302  case 0x1FB7F:
303  return 0xBA; // RIGHT AND LOWER ONE EIGHTH BLOCK
304  case 0x2596:
305  return 0xBB; // QUADRANT LOWER LEFT
306  case 0x259D:
307  return 0xBC; // QUADRANT UPPER RIGHT
308  case 0x2518:
309  return 0xBD; // BOX DRAWINGS LIGHT UP AND LEFT
310  case 0x2598:
311  return 0xBE; // QUADRANT UPPER LEFT
312  case 0x259A:
313  return 0xBF; // QUADRANT UPPER LEFT AND LOWER RIGHT
314  }
315  }
316 };
317 
318 template <size_t N> struct ShiftedString {
319  char Str[N]{};
320 
321  constexpr ShiftedString(char const (&Src)[N]) {
322  for (size_t I = 0; I < N; ++I) {
323  if (Src[I] >= 0x80)
324  throw "use U prefix for unicode string literals";
325  Str[I] = TranslateUnicode(Src[I]);
326  }
327  }
328 
329  constexpr ShiftedString(char16_t const (&Src)[N]) {
330  for (size_t I = 0; I < N; ++I) {
331  if (Src[I] >= 0xD800 && Src[I] <= 0xDFFF)
332  throw "use U prefix for unicode string literals";
333  Str[I] = TranslateUnicode(Src[I]);
334  }
335  }
336 
337  constexpr ShiftedString(char32_t const (&Src)[N]) {
338  for (size_t I = 0; I < N; ++I)
339  Str[I] = TranslateUnicode(Src[I]);
340  }
341 
342  constexpr char TranslateUnicode(char32_t C) {
343  switch (C) {
344  default:
345  throw "Unsupported";
346 
347  // C0 control codes are uninterpreted.
348  case 0x0000 ... 0x001f:
349  return C;
350 
351  // Name: Map from Commodore PET (interchange) alternate character set to
352  // Unicode
353 
354  // Date: 2018 October 11
355 
356  // Author: Rebecca Bettencourt <support@kreativekorp.com>
357 
358  case 0x0020:
359  return 0x20; // SPACE
360  case 0x0021:
361  return 0x21; // EXCLAMATION MARK
362  case 0x0022:
363  return 0x22; // QUOTATION MARK
364  case 0x0023:
365  return 0x23; // NUMBER SIGN
366  case 0x0024:
367  return 0x24; // DOLLAR SIGN
368  case 0x0025:
369  return 0x25; // PERCENT SIGN
370  case 0x0026:
371  return 0x26; // AMPERSAND
372  case 0x0027:
373  return 0x27; // APOSTROPHE
374  case 0x0028:
375  return 0x28; // LEFT PARENTHESIS
376  case 0x0029:
377  return 0x29; // RIGHT PARENTHESIS
378  case 0x002A:
379  return 0x2A; // ASTERISK
380  case 0x002B:
381  return 0x2B; // PLUS SIGN
382  case 0x002C:
383  return 0x2C; // COMMA
384  case 0x002D:
385  return 0x2D; // HYPHEN-MINUS
386  case 0x002E:
387  return 0x2E; // FULL STOP
388  case 0x002F:
389  return 0x2F; // SOLIDUS
390  case 0x0030:
391  return 0x30; // DIGIT ZERO
392  case 0x0031:
393  return 0x31; // DIGIT ONE
394  case 0x0032:
395  return 0x32; // DIGIT TWO
396  case 0x0033:
397  return 0x33; // DIGIT THREE
398  case 0x0034:
399  return 0x34; // DIGIT FOUR
400  case 0x0035:
401  return 0x35; // DIGIT FIVE
402  case 0x0036:
403  return 0x36; // DIGIT SIX
404  case 0x0037:
405  return 0x37; // DIGIT SEVEN
406  case 0x0038:
407  return 0x38; // DIGIT EIGHT
408  case 0x0039:
409  return 0x39; // DIGIT NINE
410  case 0x003A:
411  return 0x3A; // COLON
412  case 0x003B:
413  return 0x3B; // SEMICOLON
414  case 0x003C:
415  return 0x3C; // LESS-THAN SIGN
416  case 0x003D:
417  return 0x3D; // EQUALS SIGN
418  case 0x003E:
419  return 0x3E; // GREATER-THAN SIGN
420  case 0x003F:
421  return 0x3F; // QUESTION MARK
422  case 0x0040:
423  return 0x40; // COMMERCIAL AT
424  case 0x0061:
425  return 0x41; // LATIN SMALL LETTER A
426  case 0x0062:
427  return 0x42; // LATIN SMALL LETTER B
428  case 0x0063:
429  return 0x43; // LATIN SMALL LETTER C
430  case 0x0064:
431  return 0x44; // LATIN SMALL LETTER D
432  case 0x0065:
433  return 0x45; // LATIN SMALL LETTER E
434  case 0x0066:
435  return 0x46; // LATIN SMALL LETTER F
436  case 0x0067:
437  return 0x47; // LATIN SMALL LETTER G
438  case 0x0068:
439  return 0x48; // LATIN SMALL LETTER H
440  case 0x0069:
441  return 0x49; // LATIN SMALL LETTER I
442  case 0x006A:
443  return 0x4A; // LATIN SMALL LETTER J
444  case 0x006B:
445  return 0x4B; // LATIN SMALL LETTER K
446  case 0x006C:
447  return 0x4C; // LATIN SMALL LETTER L
448  case 0x006D:
449  return 0x4D; // LATIN SMALL LETTER M
450  case 0x006E:
451  return 0x4E; // LATIN SMALL LETTER N
452  case 0x006F:
453  return 0x4F; // LATIN SMALL LETTER O
454  case 0x0070:
455  return 0x50; // LATIN SMALL LETTER P
456  case 0x0071:
457  return 0x51; // LATIN SMALL LETTER Q
458  case 0x0072:
459  return 0x52; // LATIN SMALL LETTER R
460  case 0x0073:
461  return 0x53; // LATIN SMALL LETTER S
462  case 0x0074:
463  return 0x54; // LATIN SMALL LETTER T
464  case 0x0075:
465  return 0x55; // LATIN SMALL LETTER U
466  case 0x0076:
467  return 0x56; // LATIN SMALL LETTER V
468  case 0x0077:
469  return 0x57; // LATIN SMALL LETTER W
470  case 0x0078:
471  return 0x58; // LATIN SMALL LETTER X
472  case 0x0079:
473  return 0x59; // LATIN SMALL LETTER Y
474  case 0x007A:
475  return 0x5A; // LATIN SMALL LETTER Z
476  case 0x005B:
477  return 0x5B; // LEFT SQUARE BRACKET
478  case 0x005C:
479  return 0x5C; // REVERSE SOLIDUS
480  case 0x005D:
481  return 0x5D; // RIGHT SQUARE BRACKET
482  case 0x2191:
483  return 0x5E; // UPWARDS ARROW
484  case 0x2190:
485  return 0x5F; // LEFTWARDS ARROW
486  case 0x2500:
487  return 0x60; // BOX DRAWINGS LIGHT HORIZONTAL
488  case 0x0041:
489  return 0x61; // LATIN CAPITAL LETTER A
490  case 0x0042:
491  return 0x62; // LATIN CAPITAL LETTER B
492  case 0x0043:
493  return 0x63; // LATIN CAPITAL LETTER C
494  case 0x0044:
495  return 0x64; // LATIN CAPITAL LETTER D
496  case 0x0045:
497  return 0x65; // LATIN CAPITAL LETTER E
498  case 0x0046:
499  return 0x66; // LATIN CAPITAL LETTER F
500  case 0x0047:
501  return 0x67; // LATIN CAPITAL LETTER G
502  case 0x0048:
503  return 0x68; // LATIN CAPITAL LETTER H
504  case 0x0049:
505  return 0x69; // LATIN CAPITAL LETTER I
506  case 0x004A:
507  return 0x6A; // LATIN CAPITAL LETTER J
508  case 0x004B:
509  return 0x6B; // LATIN CAPITAL LETTER K
510  case 0x004C:
511  return 0x6C; // LATIN CAPITAL LETTER L
512  case 0x004D:
513  return 0x6D; // LATIN CAPITAL LETTER M
514  case 0x004E:
515  return 0x6E; // LATIN CAPITAL LETTER N
516  case 0x004F:
517  return 0x6F; // LATIN CAPITAL LETTER O
518  case 0x0050:
519  return 0x70; // LATIN CAPITAL LETTER P
520  case 0x0051:
521  return 0x71; // LATIN CAPITAL LETTER Q
522  case 0x0052:
523  return 0x72; // LATIN CAPITAL LETTER R
524  case 0x0053:
525  return 0x73; // LATIN CAPITAL LETTER S
526  case 0x0054:
527  return 0x74; // LATIN CAPITAL LETTER T
528  case 0x0055:
529  return 0x75; // LATIN CAPITAL LETTER U
530  case 0x0056:
531  return 0x76; // LATIN CAPITAL LETTER V
532  case 0x0057:
533  return 0x77; // LATIN CAPITAL LETTER W
534  case 0x0058:
535  return 0x78; // LATIN CAPITAL LETTER X
536  case 0x0059:
537  return 0x79; // LATIN CAPITAL LETTER Y
538  case 0x005A:
539  return 0x7A; // LATIN CAPITAL LETTER Z
540  case 0x253C:
541  return 0x7B; // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
542  case 0x1FB8C:
543  return 0x7C; // LEFT HALF MEDIUM SHADE
544  case 0x2502:
545  return 0x7D; // BOX DRAWINGS LIGHT VERTICAL
546  case 0x1FB95:
547  return 0x7E; // CHECKER BOARD FILL
548  case 0x1FB98:
549  return 0x7F; // UPPER LEFT TO LOWER RIGHT FILL
550  case 0x00A0:
551  return 0xA0; // NO-BREAK SPACE
552  case 0x258C:
553  return 0xA1; // LEFT HALF BLOCK
554  case 0x2584:
555  return 0xA2; // LOWER HALF BLOCK
556  case 0x2594:
557  return 0xA3; // UPPER ONE EIGHTH BLOCK
558  case 0x2581:
559  return 0xA4; // LOWER ONE EIGHTH BLOCK
560  case 0x258F:
561  return 0xA5; // LEFT ONE EIGHTH BLOCK
562  case 0x2592:
563  return 0xA6; // MEDIUM SHADE
564  case 0x2595:
565  return 0xA7; // RIGHT ONE EIGHTH BLOCK
566  case 0x1FB8F:
567  return 0xA8; // LOWER HALF MEDIUM SHADE
568  case 0x1FB99:
569  return 0xA9; // UPPER RIGHT TO LOWER LEFT FILL
570  case 0x1FB87:
571  return 0xAA; // RIGHT ONE QUARTER BLOCK
572  case 0x251C:
573  return 0xAB; // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
574  case 0x2597:
575  return 0xAC; // QUADRANT LOWER RIGHT
576  case 0x2514:
577  return 0xAD; // BOX DRAWINGS LIGHT UP AND RIGHT
578  case 0x2510:
579  return 0xAE; // BOX DRAWINGS LIGHT DOWN AND LEFT
580  case 0x2582:
581  return 0xAF; // LOWER ONE QUARTER BLOCK
582  case 0x250C:
583  return 0xB0; // BOX DRAWINGS LIGHT DOWN AND RIGHT
584  case 0x2534:
585  return 0xB1; // BOX DRAWINGS LIGHT UP AND HORIZONTAL
586  case 0x252C:
587  return 0xB2; // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
588  case 0x2524:
589  return 0xB3; // BOX DRAWINGS LIGHT VERTICAL AND LEFT
590  case 0x258E:
591  return 0xB4; // LEFT ONE QUARTER BLOCK
592  case 0x258D:
593  return 0xB5; // LEFT THREE EIGHTHS BLOCK
594  case 0x1FB88:
595  return 0xB6; // RIGHT THREE EIGHTHS BLOCK
596  case 0x1FB82:
597  return 0xB7; // UPPER ONE QUARTER BLOCK
598  case 0x1FB83:
599  return 0xB8; // UPPER THREE EIGHTHS BLOCK
600  case 0x2583:
601  return 0xB9; // LOWER THREE EIGHTHS BLOCK
602  case 0x2713:
603  return 0xBA; // CHECK MARK
604  case 0x2596:
605  return 0xBB; // QUADRANT LOWER LEFT
606  case 0x259D:
607  return 0xBC; // QUADRANT UPPER RIGHT
608  case 0x2518:
609  return 0xBD; // BOX DRAWINGS LIGHT UP AND LEFT
610  case 0x2598:
611  return 0xBE; // QUADRANT UPPER LEFT
612  case 0x259A:
613  return 0xBF; // QUADRANT UPPER LEFT AND LOWER RIGHT
614  }
615  }
616 };
617 
618 template <size_t N> struct UnshiftedVideoString {
619  char Str[N]{};
620 
621  constexpr UnshiftedVideoString(char const (&Src)[N]) {
622  for (size_t I = 0; I < N; ++I) {
623  if (Src[I] >= 0x80)
624  throw "use U prefix for unicode string literals";
625  Str[I] = TranslateUnicode(Src[I]);
626  }
627  }
628 
629  constexpr UnshiftedVideoString(char16_t const (&Src)[N]) {
630  for (size_t I = 0; I < N; ++I) {
631  if (Src[I] >= 0xD800 && Src[I] <= 0xDFFF)
632  throw "use U prefix for unicode string literals";
633  Str[I] = TranslateUnicode(Src[I]);
634  }
635  }
636 
637  constexpr UnshiftedVideoString(char32_t const (&Src)[N]) {
638  for (size_t I = 0; I < N; ++I)
639  Str[I] = TranslateUnicode(Src[I]);
640  }
641 
642  constexpr char TranslateUnicode(char32_t C) {
643  switch (C) {
644  default:
645  throw "Unsupported";
646 
647  // Preserve NUL
648  case 0x0000:
649  return 0x00;
650 
651  // Name: Map from Commodore 64/128 (video) primary character set to
652  // Unicode
653 
654  // Date: 2018 April 20
655 
656  // Author: Rebecca Bettencourt <support@kreativekorp.com>
657 
658  case 0x0040:
659  return 0x00; // COMMERCIAL AT
660  case 0x0041:
661  return 0x01; // LATIN CAPITAL LETTER A
662  case 0x0042:
663  return 0x02; // LATIN CAPITAL LETTER B
664  case 0x0043:
665  return 0x03; // LATIN CAPITAL LETTER C
666  case 0x0044:
667  return 0x04; // LATIN CAPITAL LETTER D
668  case 0x0045:
669  return 0x05; // LATIN CAPITAL LETTER E
670  case 0x0046:
671  return 0x06; // LATIN CAPITAL LETTER F
672  case 0x0047:
673  return 0x07; // LATIN CAPITAL LETTER G
674  case 0x0048:
675  return 0x08; // LATIN CAPITAL LETTER H
676  case 0x0049:
677  return 0x09; // LATIN CAPITAL LETTER I
678  case 0x004A:
679  return 0x0A; // LATIN CAPITAL LETTER J
680  case 0x004B:
681  return 0x0B; // LATIN CAPITAL LETTER K
682  case 0x004C:
683  return 0x0C; // LATIN CAPITAL LETTER L
684  case 0x004D:
685  return 0x0D; // LATIN CAPITAL LETTER M
686  case 0x004E:
687  return 0x0E; // LATIN CAPITAL LETTER N
688  case 0x004F:
689  return 0x0F; // LATIN CAPITAL LETTER O
690  case 0x0050:
691  return 0x10; // LATIN CAPITAL LETTER P
692  case 0x0051:
693  return 0x11; // LATIN CAPITAL LETTER Q
694  case 0x0052:
695  return 0x12; // LATIN CAPITAL LETTER R
696  case 0x0053:
697  return 0x13; // LATIN CAPITAL LETTER S
698  case 0x0054:
699  return 0x14; // LATIN CAPITAL LETTER T
700  case 0x0055:
701  return 0x15; // LATIN CAPITAL LETTER U
702  case 0x0056:
703  return 0x16; // LATIN CAPITAL LETTER V
704  case 0x0057:
705  return 0x17; // LATIN CAPITAL LETTER W
706  case 0x0058:
707  return 0x18; // LATIN CAPITAL LETTER X
708  case 0x0059:
709  return 0x19; // LATIN CAPITAL LETTER Y
710  case 0x005A:
711  return 0x1A; // LATIN CAPITAL LETTER Z
712  case 0x005B:
713  return 0x1B; // LEFT SQUARE BRACKET
714  case 0x005C:
715  return 0x1C; // REVERSE SOLIDUS
716  case 0x005D:
717  return 0x1D; // RIGHT SQUARE BRACKET
718  case 0x2191:
719  return 0x1E; // UPWARDS ARROW
720  case 0x2190:
721  return 0x1F; // LEFTWARDS ARROW
722  case 0x0020:
723  return 0x20; // SPACE
724  case 0x0021:
725  return 0x21; // EXCLAMATION MARK
726  case 0x0022:
727  return 0x22; // QUOTATION MARK
728  case 0x0023:
729  return 0x23; // NUMBER SIGN
730  case 0x0024:
731  return 0x24; // DOLLAR SIGN
732  case 0x0025:
733  return 0x25; // PERCENT SIGN
734  case 0x0026:
735  return 0x26; // AMPERSAND
736  case 0x0027:
737  return 0x27; // APOSTROPHE
738  case 0x0028:
739  return 0x28; // LEFT PARENTHESIS
740  case 0x0029:
741  return 0x29; // RIGHT PARENTHESIS
742  case 0x002A:
743  return 0x2A; // ASTERISK
744  case 0x002B:
745  return 0x2B; // PLUS SIGN
746  case 0x002C:
747  return 0x2C; // COMMA
748  case 0x002D:
749  return 0x2D; // HYPHEN-MINUS
750  case 0x002E:
751  return 0x2E; // FULL STOP
752  case 0x002F:
753  return 0x2F; // SOLIDUS
754  case 0x0030:
755  return 0x30; // DIGIT ZERO
756  case 0x0031:
757  return 0x31; // DIGIT ONE
758  case 0x0032:
759  return 0x32; // DIGIT TWO
760  case 0x0033:
761  return 0x33; // DIGIT THREE
762  case 0x0034:
763  return 0x34; // DIGIT FOUR
764  case 0x0035:
765  return 0x35; // DIGIT FIVE
766  case 0x0036:
767  return 0x36; // DIGIT SIX
768  case 0x0037:
769  return 0x37; // DIGIT SEVEN
770  case 0x0038:
771  return 0x38; // DIGIT EIGHT
772  case 0x0039:
773  return 0x39; // DIGIT NINE
774  case 0x003A:
775  return 0x3A; // COLON
776  case 0x003B:
777  return 0x3B; // SEMICOLON
778  case 0x003C:
779  return 0x3C; // LESS-THAN SIGN
780  case 0x003D:
781  return 0x3D; // EQUALS SIGN
782  case 0x003E:
783  return 0x3E; // GREATER-THAN SIGN
784  case 0x003F:
785  return 0x3F; // QUESTION MARK
786  case 0x2500:
787  return 0x40; // BOX DRAWINGS LIGHT HORIZONTAL
788  case 0x2660:
789  return 0x41; // BLACK SPADE SUIT
790  case 0x1FB72:
791  return 0x42; // VERTICAL ONE EIGHTH BLOCK-4
792  case 0x1FB78:
793  return 0x43; // HORIZONTAL ONE EIGHTH BLOCK-4
794  case 0x1FB77:
795  return 0x44; // HORIZONTAL ONE EIGHTH BLOCK-3
796  case 0x1FB76:
797  return 0x45; // HORIZONTAL ONE EIGHTH BLOCK-2
798  case 0x1FB7A:
799  return 0x46; // HORIZONTAL ONE EIGHTH BLOCK-6
800  case 0x1FB71:
801  return 0x47; // VERTICAL ONE EIGHTH BLOCK-3
802  case 0x1FB74:
803  return 0x48; // VERTICAL ONE EIGHTH BLOCK-6
804  case 0x256E:
805  return 0x49; // BOX DRAWINGS LIGHT ARC DOWN AND LEFT
806  case 0x2570:
807  return 0x4A; // BOX DRAWINGS LIGHT ARC UP AND RIGHT
808  case 0x256F:
809  return 0x4B; // BOX DRAWINGS LIGHT ARC UP AND LEFT
810  case 0x1FB7C:
811  return 0x4C; // LEFT AND LOWER ONE EIGHTH BLOCK
812  case 0x2572:
813  return 0x4D; // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
814  case 0x2571:
815  return 0x4E; // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
816  case 0x1FB7D:
817  return 0x4F; // LEFT AND UPPER ONE EIGHTH BLOCK
818  case 0x1FB7E:
819  return 0x50; // RIGHT AND UPPER ONE EIGHTH BLOCK
820  case 0x2022:
821  case 0x25CF:
822  return 0x51; // BULLET (or 0x25CF BLACK CIRCLE)
823  case 0x1FB7B:
824  return 0x52; // HORIZONTAL ONE EIGHTH BLOCK-7
825  case 0x2665:
826  return 0x53; // BLACK HEART SUIT
827  case 0x1FB70:
828  return 0x54; // VERTICAL ONE EIGHTH BLOCK-2
829  case 0x256D:
830  return 0x55; // BOX DRAWINGS LIGHT ARC DOWN AND RIGHT
831  case 0x2573:
832  return 0x56; // BOX DRAWINGS LIGHT DIAGONAL CROSS
833  case 0x25CB:
834  case 0x25E6:
835  return 0x57; // WHITE CIRCLE (or 0x25E6 WHITE BULLET)
836  case 0x2663:
837  return 0x58; // BLACK CLUB SUIT
838  case 0x1FB75:
839  return 0x59; // VERTICAL ONE EIGHTH BLOCK-7
840  case 0x2666:
841  return 0x5A; // BLACK DIAMOND SUIT
842  case 0x253C:
843  return 0x5B; // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
844  case 0x1FB8C:
845  return 0x5C; // LEFT HALF MEDIUM SHADE
846  case 0x2502:
847  return 0x5D; // BOX DRAWINGS LIGHT VERTICAL
848  case 0x03C0:
849  return 0x5E; // GREEK SMALL LETTER PI
850  case 0x25E5:
851  return 0x5F; // BLACK UPPER RIGHT TRIANGLE
852  case 0x00A0:
853  return 0x60; // NO-BREAK SPACE
854  case 0x258C:
855  return 0x61; // LEFT HALF BLOCK
856  case 0x2584:
857  return 0x62; // LOWER HALF BLOCK
858  case 0x2594:
859  return 0x63; // UPPER ONE EIGHTH BLOCK
860  case 0x2581:
861  return 0x64; // LOWER ONE EIGHTH BLOCK
862  case 0x258F:
863  return 0x65; // LEFT ONE EIGHTH BLOCK
864  case 0x2592:
865  return 0x66; // MEDIUM SHADE
866  case 0x2595:
867  return 0x67; // RIGHT ONE EIGHTH BLOCK
868  case 0x1FB8F:
869  return 0x68; // LOWER HALF MEDIUM SHADE
870  case 0x25E4:
871  return 0x69; // BLACK UPPER LEFT TRIANGLE
872  case 0x1FB87:
873  return 0x6A; // RIGHT ONE QUARTER BLOCK
874  case 0x251C:
875  return 0x6B; // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
876  case 0x2597:
877  return 0x6C; // QUADRANT LOWER RIGHT
878  case 0x2514:
879  return 0x6D; // BOX DRAWINGS LIGHT UP AND RIGHT
880  case 0x2510:
881  return 0x6E; // BOX DRAWINGS LIGHT DOWN AND LEFT
882  case 0x2582:
883  return 0x6F; // LOWER ONE QUARTER BLOCK
884  case 0x250C:
885  return 0x70; // BOX DRAWINGS LIGHT DOWN AND RIGHT
886  case 0x2534:
887  return 0x71; // BOX DRAWINGS LIGHT UP AND HORIZONTAL
888  case 0x252C:
889  return 0x72; // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
890  case 0x2524:
891  return 0x73; // BOX DRAWINGS LIGHT VERTICAL AND LEFT
892  case 0x258E:
893  return 0x74; // LEFT ONE QUARTER BLOCK
894  case 0x258D:
895  return 0x75; // LEFT THREE EIGHTHS BLOCK
896  case 0x1FB88:
897  return 0x76; // RIGHT THREE EIGHTHS BLOCK
898  case 0x1FB82:
899  return 0x77; // UPPER ONE QUARTER BLOCK
900  case 0x1FB83:
901  return 0x78; // UPPER THREE EIGHTHS BLOCK
902  case 0x2583:
903  return 0x79; // LOWER THREE EIGHTHS BLOCK
904  case 0x1FB7F:
905  return 0x7A; // RIGHT AND LOWER ONE EIGHTH BLOCK
906  case 0x2596:
907  return 0x7B; // QUADRANT LOWER LEFT
908  case 0x259D:
909  return 0x7C; // QUADRANT UPPER RIGHT
910  case 0x2518:
911  return 0x7D; // BOX DRAWINGS LIGHT UP AND LEFT
912  case 0x2598:
913  return 0x7E; // QUADRANT UPPER LEFT
914  case 0x259A:
915  return 0x7F; // QUADRANT UPPER LEFT AND LOWER RIGHT
916  case 0x25D8:
917  return 0xD1; // INVERSE BULLET
918  case 0x25D9:
919  return 0xD7; // INVERSE WHITE CIRCLE
920  case 0x1FB94:
921  return 0xDC; // LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK
922  case 0x25E3:
923  return 0xDF; // BLACK LOWER LEFT TRIANGLE
924  case 0x2588:
925  return 0xE0; // FULL BLOCK
926  case 0x2590:
927  return 0xE1; // RIGHT HALF BLOCK
928  case 0x2580:
929  return 0xE2; // UPPER HALF BLOCK
930  case 0x2587:
931  return 0xE3; // LOWER SEVEN EIGHTHS BLOCK
932  case 0x1FB86:
933  return 0xE4; // UPPER SEVEN EIGHTHS BLOCK
934  case 0x1FB8B:
935  return 0xE5; // RIGHT SEVEN EIGHTHS BLOCK
936  case 0x1FB90:
937  return 0xE6; // INVERSE MEDIUM SHADE
938  case 0x2589:
939  return 0xE7; // LEFT SEVEN EIGHTHS BLOCK
940  case 0x1FB91:
941  return 0xE8; // UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE
942  case 0x25E2:
943  return 0xE9; // BLACK LOWER RIGHT TRIANGLE
944  case 0x258A:
945  return 0xEA; // LEFT THREE QUARTERS BLOCK
946  case 0x259B:
947  return 0xEC; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT
948  case 0x1FB85:
949  return 0xEF; // UPPER THREE QUARTERS BLOCK
950  case 0x1FB8A:
951  return 0xF4; // RIGHT THREE QUARTERS BLOCK
952  case 0x1FB89:
953  return 0xF5; // RIGHT FIVE EIGHTHS BLOCK
954  case 0x258B:
955  return 0xF6; // LEFT FIVE EIGHTHS BLOCK
956  case 0x2586:
957  return 0xF7; // LOWER THREE QUARTERS BLOCK
958  case 0x2585:
959  return 0xF8; // LOWER FIVE EIGHTHS BLOCK
960  case 0x1FB84:
961  return 0xF9; // UPPER FIVE EIGHTHS BLOCK
962  case 0x259C:
963  return 0xFB; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT
964  case 0x2599:
965  return 0xFC; // QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT
966  case 0x259F:
967  return 0xFE; // QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
968  case 0x259E:
969  return 0xFF; // QUADRANT UPPER RIGHT AND LOWER LEFT
970  }
971  }
972 };
973 
974 template <size_t N> struct UnshiftedReverseVideoString {
975  char Str[N]{};
976 
977  constexpr UnshiftedReverseVideoString(char const (&Src)[N]) {
978  for (size_t I = 0; I < N; ++I) {
979  if (Src[I] >= 0x80)
980  throw "use U prefix for unicode string literals";
981  Str[I] = TranslateUnicode(Src[I]);
982  }
983  }
984 
985  constexpr UnshiftedReverseVideoString(char16_t const (&Src)[N]) {
986  for (size_t I = 0; I < N; ++I) {
987  if (Src[I] >= 0xD800 && Src[I] <= 0xDFFF)
988  throw "use U prefix for unicode string literals";
989  Str[I] = TranslateUnicode(Src[I]);
990  }
991  }
992 
993  constexpr UnshiftedReverseVideoString(char32_t const (&Src)[N]) {
994  for (size_t I = 0; I < N; ++I)
995  Str[I] = TranslateUnicode(Src[I]);
996  }
997 
998  constexpr char TranslateUnicode(char32_t C) {
999  switch (C) {
1000  default:
1001  throw "Unsupported";
1002 
1003  // Preserve NUL
1004  case 0x0000:
1005  return 0x00;
1006 
1007  // Name: Map from Commodore 64/128 (video) primary character set to
1008  // Unicode
1009 
1010  // Date: 2018 April 20
1011 
1012  // Author: Rebecca Bettencourt <support@kreativekorp.com>
1013 
1014  case 0x25D8:
1015  return 0x51; // INVERSE BULLET
1016  case 0x25D9:
1017  return 0x57; // INVERSE WHITE CIRCLE
1018  case 0x25E3:
1019  return 0x5F; // BLACK LOWER LEFT TRIANGLE
1020  case 0x2588:
1021  return 0x60; // FULL BLOCK
1022  case 0x2590:
1023  return 0x61; // RIGHT HALF BLOCK
1024  case 0x2580:
1025  return 0x62; // UPPER HALF BLOCK
1026  case 0x2587:
1027  return 0x63; // LOWER SEVEN EIGHTHS BLOCK
1028  case 0x1FB86:
1029  return 0x64; // UPPER SEVEN EIGHTHS BLOCK
1030  case 0x1FB8B:
1031  return 0x65; // RIGHT SEVEN EIGHTHS BLOCK
1032  case 0x1FB90:
1033  return 0x66; // INVERSE MEDIUM SHADE
1034  case 0x2589:
1035  return 0x67; // LEFT SEVEN EIGHTHS BLOCK
1036  case 0x1FB91:
1037  return 0x68; // UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE
1038  case 0x25E2:
1039  return 0x69; // BLACK LOWER RIGHT TRIANGLE
1040  case 0x258A:
1041  return 0x6A; // LEFT THREE QUARTERS BLOCK
1042  case 0x259B:
1043  return 0x6C; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT
1044  case 0x1FB85:
1045  return 0x6F; // UPPER THREE QUARTERS BLOCK
1046  case 0x1FB8A:
1047  return 0x74; // RIGHT THREE QUARTERS BLOCK
1048  case 0x1FB89:
1049  return 0x75; // RIGHT FIVE EIGHTHS BLOCK
1050  case 0x258B:
1051  return 0x76; // LEFT FIVE EIGHTHS BLOCK
1052  case 0x2586:
1053  return 0x77; // LOWER THREE QUARTERS BLOCK
1054  case 0x2585:
1055  return 0x78; // LOWER FIVE EIGHTHS BLOCK
1056  case 0x1FB84:
1057  return 0x79; // UPPER FIVE EIGHTHS BLOCK
1058  case 0x259C:
1059  return 0x7B; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT
1060  case 0x2599:
1061  return 0x7C; // QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT
1062  case 0x259F:
1063  return 0x7E; // QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
1064  case 0x259E:
1065  return 0x7F; // QUADRANT UPPER RIGHT AND LOWER LEFT
1066  case 0x0040:
1067  return 0x80; // COMMERCIAL AT
1068  case 0x1FB94:
1069  return 0x5C; // LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK
1070  case 0x0041:
1071  return 0x81; // LATIN CAPITAL LETTER A
1072  case 0x0042:
1073  return 0x82; // LATIN CAPITAL LETTER B
1074  case 0x0043:
1075  return 0x83; // LATIN CAPITAL LETTER C
1076  case 0x0044:
1077  return 0x84; // LATIN CAPITAL LETTER D
1078  case 0x0045:
1079  return 0x85; // LATIN CAPITAL LETTER E
1080  case 0x0046:
1081  return 0x86; // LATIN CAPITAL LETTER F
1082  case 0x0047:
1083  return 0x87; // LATIN CAPITAL LETTER G
1084  case 0x0048:
1085  return 0x88; // LATIN CAPITAL LETTER H
1086  case 0x0049:
1087  return 0x89; // LATIN CAPITAL LETTER I
1088  case 0x004A:
1089  return 0x8A; // LATIN CAPITAL LETTER J
1090  case 0x004B:
1091  return 0x8B; // LATIN CAPITAL LETTER K
1092  case 0x004C:
1093  return 0x8C; // LATIN CAPITAL LETTER L
1094  case 0x004D:
1095  return 0x8D; // LATIN CAPITAL LETTER M
1096  case 0x004E:
1097  return 0x8E; // LATIN CAPITAL LETTER N
1098  case 0x004F:
1099  return 0x8F; // LATIN CAPITAL LETTER O
1100  case 0x0050:
1101  return 0x90; // LATIN CAPITAL LETTER P
1102  case 0x0051:
1103  return 0x91; // LATIN CAPITAL LETTER Q
1104  case 0x0052:
1105  return 0x92; // LATIN CAPITAL LETTER R
1106  case 0x0053:
1107  return 0x93; // LATIN CAPITAL LETTER S
1108  case 0x0054:
1109  return 0x94; // LATIN CAPITAL LETTER T
1110  case 0x0055:
1111  return 0x95; // LATIN CAPITAL LETTER U
1112  case 0x0056:
1113  return 0x96; // LATIN CAPITAL LETTER V
1114  case 0x0057:
1115  return 0x97; // LATIN CAPITAL LETTER W
1116  case 0x0058:
1117  return 0x98; // LATIN CAPITAL LETTER X
1118  case 0x0059:
1119  return 0x99; // LATIN CAPITAL LETTER Y
1120  case 0x005A:
1121  return 0x9A; // LATIN CAPITAL LETTER Z
1122  case 0x005B:
1123  return 0x9B; // LEFT SQUARE BRACKET
1124  case 0x005C:
1125  return 0x9C; // REVERSE SOLIDUS
1126  case 0x005D:
1127  return 0x9D; // RIGHT SQUARE BRACKET
1128  case 0x2191:
1129  return 0x9E; // UPWARDS ARROW
1130  case 0x2190:
1131  return 0x9F; // LEFTWARDS ARROW
1132  case 0x0020:
1133  return 0xA0; // SPACE
1134  case 0x0021:
1135  return 0xA1; // EXCLAMATION MARK
1136  case 0x0022:
1137  return 0xA2; // QUOTATION MARK
1138  case 0x0023:
1139  return 0xA3; // NUMBER SIGN
1140  case 0x0024:
1141  return 0xA4; // DOLLAR SIGN
1142  case 0x0025:
1143  return 0xA5; // PERCENT SIGN
1144  case 0x0026:
1145  return 0xA6; // AMPERSAND
1146  case 0x0027:
1147  return 0xA7; // APOSTROPHE
1148  case 0x0028:
1149  return 0xA8; // LEFT PARENTHESIS
1150  case 0x0029:
1151  return 0xA9; // RIGHT PARENTHESIS
1152  case 0x002A:
1153  return 0xAA; // ASTERISK
1154  case 0x002B:
1155  return 0xAB; // PLUS SIGN
1156  case 0x002C:
1157  return 0xAC; // COMMA
1158  case 0x002D:
1159  return 0xAD; // HYPHEN-MINUS
1160  case 0x002E:
1161  return 0xAE; // FULL STOP
1162  case 0x002F:
1163  return 0xAF; // SOLIDUS
1164  case 0x0030:
1165  return 0xB0; // DIGIT ZERO
1166  case 0x0031:
1167  return 0xB1; // DIGIT ONE
1168  case 0x0032:
1169  return 0xB2; // DIGIT TWO
1170  case 0x0033:
1171  return 0xB3; // DIGIT THREE
1172  case 0x0034:
1173  return 0xB4; // DIGIT FOUR
1174  case 0x0035:
1175  return 0xB5; // DIGIT FIVE
1176  case 0x0036:
1177  return 0xB6; // DIGIT SIX
1178  case 0x0037:
1179  return 0xB7; // DIGIT SEVEN
1180  case 0x0038:
1181  return 0xB8; // DIGIT EIGHT
1182  case 0x0039:
1183  return 0xB9; // DIGIT NINE
1184  case 0x003A:
1185  return 0xBA; // COLON
1186  case 0x003B:
1187  return 0xBB; // SEMICOLON
1188  case 0x003C:
1189  return 0xBC; // LESS-THAN SIGN
1190  case 0x003D:
1191  return 0xBD; // EQUALS SIGN
1192  case 0x003E:
1193  return 0xBE; // GREATER-THAN SIGN
1194  case 0x003F:
1195  return 0xBF; // QUESTION MARK
1196  case 0x2500:
1197  return 0xC0; // BOX DRAWINGS LIGHT HORIZONTAL
1198  case 0x2660:
1199  return 0xC1; // BLACK SPADE SUIT
1200  case 0x1FB72:
1201  return 0xC2; // VERTICAL ONE EIGHTH BLOCK-4
1202  case 0x1FB78:
1203  return 0xC3; // HORIZONTAL ONE EIGHTH BLOCK-4
1204  case 0x1FB77:
1205  return 0xC4; // HORIZONTAL ONE EIGHTH BLOCK-3
1206  case 0x1FB76:
1207  return 0xC5; // HORIZONTAL ONE EIGHTH BLOCK-2
1208  case 0x1FB7A:
1209  return 0xC6; // HORIZONTAL ONE EIGHTH BLOCK-6
1210  case 0x1FB71:
1211  return 0xC7; // VERTICAL ONE EIGHTH BLOCK-3
1212  case 0x1FB74:
1213  return 0xC8; // VERTICAL ONE EIGHTH BLOCK-6
1214  case 0x256E:
1215  return 0xC9; // BOX DRAWINGS LIGHT ARC DOWN AND LEFT
1216  case 0x2570:
1217  return 0xCA; // BOX DRAWINGS LIGHT ARC UP AND RIGHT
1218  case 0x256F:
1219  return 0xCB; // BOX DRAWINGS LIGHT ARC UP AND LEFT
1220  case 0x1FB7C:
1221  return 0xCC; // LEFT AND LOWER ONE EIGHTH BLOCK
1222  case 0x2572:
1223  return 0xCD; // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
1224  case 0x2571:
1225  return 0xCE; // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
1226  case 0x1FB7D:
1227  return 0xCF; // LEFT AND UPPER ONE EIGHTH BLOCK
1228  case 0x1FB7E:
1229  return 0xD0; // RIGHT AND UPPER ONE EIGHTH BLOCK
1230  case 0x2022:
1231  case 0x25CF:
1232  return 0xD1; // BULLET (or 0x25CF BLACK CIRCLE)
1233  case 0x1FB7B:
1234  return 0xD2; // HORIZONTAL ONE EIGHTH BLOCK-7
1235  case 0x2665:
1236  return 0xD3; // BLACK HEART SUIT
1237  case 0x1FB70:
1238  return 0xD4; // VERTICAL ONE EIGHTH BLOCK-2
1239  case 0x256D:
1240  return 0xD5; // BOX DRAWINGS LIGHT ARC DOWN AND RIGHT
1241  case +0x2573:
1242  return 0xD6; // BOX DRAWINGS LIGHT DIAGONAL CROSS
1243  case 0x25CB:
1244  case 0x25E6:
1245  return 0xD7; // WHITE CIRCLE (or 0x25E6 WHITE BULLET)
1246  case 0x2663:
1247  return 0xD8; // BLACK CLUB SUIT
1248  case 0x1FB75:
1249  return 0xD9; // VERTICAL ONE EIGHTH BLOCK-7
1250  case 0x2666:
1251  return 0xDA; // BLACK DIAMOND SUIT
1252  case 0x253C:
1253  return 0xDB; // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
1254  case 0x1FB8C:
1255  return 0xDC; // LEFT HALF MEDIUM SHADE
1256  case 0x2502:
1257  return 0xDD; // BOX DRAWINGS LIGHT VERTICAL
1258  case 0x03C0:
1259  return 0xDE; // GREEK SMALL LETTER PI
1260  case 0x25E5:
1261  return 0xDF; // BLACK UPPER RIGHT TRIANGLE
1262  case 0x00A0:
1263  return 0xE0; // NO-BREAK SPACE
1264  case 0x258C:
1265  return 0xE1; // LEFT HALF BLOCK
1266  case 0x2584:
1267  return 0xE2; // LOWER HALF BLOCK
1268  case 0x2594:
1269  return 0xE3; // UPPER ONE EIGHTH BLOCK
1270  case 0x2581:
1271  return 0xE4; // LOWER ONE EIGHTH BLOCK
1272  case 0x258F:
1273  return 0xE5; // LEFT ONE EIGHTH BLOCK
1274  case 0x2592:
1275  return 0xE6; // MEDIUM SHADE
1276  case 0x2595:
1277  return 0xE7; // RIGHT ONE EIGHTH BLOCK
1278  case 0x1FB8F:
1279  return 0xE8; // LOWER HALF MEDIUM SHADE
1280  case 0x25E4:
1281  return 0xE9; // BLACK UPPER LEFT TRIANGLE
1282  case 0x1FB87:
1283  return 0xEA; // RIGHT ONE QUARTER BLOCK
1284  case 0x251C:
1285  return 0xEB; // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
1286  case 0x2597:
1287  return 0xEC; // QUADRANT LOWER RIGHT
1288  case 0x2514:
1289  return 0xED; // BOX DRAWINGS LIGHT UP AND RIGHT
1290  case 0x2510:
1291  return 0xEE; // BOX DRAWINGS LIGHT DOWN AND LEFT
1292  case 0x2582:
1293  return 0xEF; // LOWER ONE QUARTER BLOCK
1294  case 0x250C:
1295  return 0xF0; // BOX DRAWINGS LIGHT DOWN AND RIGHT
1296  case 0x2534:
1297  return 0xF1; // BOX DRAWINGS LIGHT UP AND HORIZONTAL
1298  case 0x252C:
1299  return 0xF2; // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
1300  case 0x2524:
1301  return 0xF3; // BOX DRAWINGS LIGHT VERTICAL AND LEFT
1302  case 0x258E:
1303  return 0xF4; // LEFT ONE QUARTER BLOCK
1304  case 0x258D:
1305  return 0xF5; // LEFT THREE EIGHTHS BLOCK
1306  case 0x1FB88:
1307  return 0xF6; // RIGHT THREE EIGHTHS BLOCK
1308  case 0x1FB82:
1309  return 0xF7; // UPPER ONE QUARTER BLOCK
1310  case 0x1FB83:
1311  return 0xF8; // UPPER THREE EIGHTHS BLOCK
1312  case 0x2583:
1313  return 0xF9; // LOWER THREE EIGHTHS BLOCK
1314  case 0x1FB7F:
1315  return 0xFA; // RIGHT AND LOWER ONE EIGHTH BLOCK
1316  case 0x2596:
1317  return 0xFB; // QUADRANT LOWER LEFT
1318  case 0x259D:
1319  return 0xFC; // QUADRANT UPPER RIGHT
1320  case 0x2518:
1321  return 0xFD; // BOX DRAWINGS LIGHT UP AND LEFT
1322  case 0x2598:
1323  return 0xFE; // QUADRANT UPPER LEFT
1324  case 0x259A:
1325  return 0xFF; // QUADRANT UPPER LEFT AND LOWER RIGHT
1326  }
1327  }
1328 };
1329 
1330 template <size_t N> struct ShiftedVideoString {
1331  char Str[N]{};
1332 
1333  constexpr ShiftedVideoString(char const (&Src)[N]) {
1334  for (size_t I = 0; I < N; ++I) {
1335  if (Src[I] >= 0x80)
1336  throw "use U prefix for unicode string literals";
1337  Str[I] = TranslateUnicode(Src[I]);
1338  }
1339  }
1340 
1341  constexpr ShiftedVideoString(char16_t const (&Src)[N]) {
1342  for (size_t I = 0; I < N; ++I) {
1343  if (Src[I] >= 0xD800 && Src[I] <= 0xDFFF)
1344  throw "use U prefix for unicode string literals";
1345  Str[I] = TranslateUnicode(Src[I]);
1346  }
1347  }
1348 
1349  constexpr ShiftedVideoString(char32_t const (&Src)[N]) {
1350  for (size_t I = 0; I < N; ++I)
1351  Str[I] = TranslateUnicode(Src[I]);
1352  }
1353 
1354  constexpr char TranslateUnicode(char32_t C) {
1355  switch (C) {
1356  default:
1357  throw "Unsupported";
1358 
1359  // Preserve NUL
1360  case 0x0000:
1361  return 0x00;
1362 
1363  // Name: Map from Commodore PET (video) alternate character set to Unicode
1364 
1365  // Date: 2018 October 11
1366 
1367  // Author: Rebecca Bettencourt <support@kreativekorp.com>
1368 
1369  case 0x0040:
1370  return 0x00; // COMMERCIAL AT
1371  case 0x0061:
1372  return 0x01; // LATIN SMALL LETTER A
1373  case 0x0062:
1374  return 0x02; // LATIN SMALL LETTER B
1375  case 0x0063:
1376  return 0x03; // LATIN SMALL LETTER C
1377  case 0x0064:
1378  return 0x04; // LATIN SMALL LETTER D
1379  case 0x0065:
1380  return 0x05; // LATIN SMALL LETTER E
1381  case 0x0066:
1382  return 0x06; // LATIN SMALL LETTER F
1383  case 0x0067:
1384  return 0x07; // LATIN SMALL LETTER G
1385  case 0x0068:
1386  return 0x08; // LATIN SMALL LETTER H
1387  case 0x0069:
1388  return 0x09; // LATIN SMALL LETTER I
1389  case 0x006A:
1390  return 0x0A; // LATIN SMALL LETTER J
1391  case 0x006B:
1392  return 0x0B; // LATIN SMALL LETTER K
1393  case 0x006C:
1394  return 0x0C; // LATIN SMALL LETTER L
1395  case 0x006D:
1396  return 0x0D; // LATIN SMALL LETTER M
1397  case 0x006E:
1398  return 0x0E; // LATIN SMALL LETTER N
1399  case 0x006F:
1400  return 0x0F; // LATIN SMALL LETTER O
1401  case 0x0070:
1402  return 0x10; // LATIN SMALL LETTER P
1403  case 0x0071:
1404  return 0x11; // LATIN SMALL LETTER Q
1405  case 0x0072:
1406  return 0x12; // LATIN SMALL LETTER R
1407  case 0x0073:
1408  return 0x13; // LATIN SMALL LETTER S
1409  case 0x0074:
1410  return 0x14; // LATIN SMALL LETTER T
1411  case 0x0075:
1412  return 0x15; // LATIN SMALL LETTER U
1413  case 0x0076:
1414  return 0x16; // LATIN SMALL LETTER V
1415  case 0x0077:
1416  return 0x17; // LATIN SMALL LETTER W
1417  case 0x0078:
1418  return 0x18; // LATIN SMALL LETTER X
1419  case 0x0079:
1420  return 0x19; // LATIN SMALL LETTER Y
1421  case 0x007A:
1422  return 0x1A; // LATIN SMALL LETTER Z
1423  case 0x005B:
1424  return 0x1B; // LEFT SQUARE BRACKET
1425  case 0x005C:
1426  return 0x1C; // REVERSE SOLIDUS
1427  case 0x005D:
1428  return 0x1D; // RIGHT SQUARE BRACKET
1429  case 0x2191:
1430  return 0x1E; // UPWARDS ARROW
1431  case 0x2190:
1432  return 0x1F; // LEFTWARDS ARROW
1433  case 0x0020:
1434  return 0x20; // SPACE
1435  case 0x0021:
1436  return 0x21; // EXCLAMATION MARK
1437  case 0x0022:
1438  return 0x22; // QUOTATION MARK
1439  case 0x0023:
1440  return 0x23; // NUMBER SIGN
1441  case 0x0024:
1442  return 0x24; // DOLLAR SIGN
1443  case 0x0025:
1444  return 0x25; // PERCENT SIGN
1445  case 0x0026:
1446  return 0x26; // AMPERSAND
1447  case 0x0027:
1448  return 0x27; // APOSTROPHE
1449  case 0x0028:
1450  return 0x28; // LEFT PARENTHESIS
1451  case 0x0029:
1452  return 0x29; // RIGHT PARENTHESIS
1453  case 0x002A:
1454  return 0x2A; // ASTERISK
1455  case 0x002B:
1456  return 0x2B; // PLUS SIGN
1457  case 0x002C:
1458  return 0x2C; // COMMA
1459  case 0x002D:
1460  return 0x2D; // HYPHEN-MINUS
1461  case 0x002E:
1462  return 0x2E; // FULL STOP
1463  case 0x002F:
1464  return 0x2F; // SOLIDUS
1465  case 0x0030:
1466  return 0x30; // DIGIT ZERO
1467  case 0x0031:
1468  return 0x31; // DIGIT ONE
1469  case 0x0032:
1470  return 0x32; // DIGIT TWO
1471  case 0x0033:
1472  return 0x33; // DIGIT THREE
1473  case 0x0034:
1474  return 0x34; // DIGIT FOUR
1475  case 0x0035:
1476  return 0x35; // DIGIT FIVE
1477  case 0x0036:
1478  return 0x36; // DIGIT SIX
1479  case 0x0037:
1480  return 0x37; // DIGIT SEVEN
1481  case 0x0038:
1482  return 0x38; // DIGIT EIGHT
1483  case 0x0039:
1484  return 0x39; // DIGIT NINE
1485  case 0x003A:
1486  return 0x3A; // COLON
1487  case 0x003B:
1488  return 0x3B; // SEMICOLON
1489  case 0x003C:
1490  return 0x3C; // LESS-THAN SIGN
1491  case 0x003D:
1492  return 0x3D; // EQUALS SIGN
1493  case 0x003E:
1494  return 0x3E; // GREATER-THAN SIGN
1495  case 0x003F:
1496  return 0x3F; // QUESTION MARK
1497  case 0x2500:
1498  return 0x40; // BOX DRAWINGS LIGHT HORIZONTAL
1499  case 0x0041:
1500  return 0x41; // LATIN CAPITAL LETTER A
1501  case 0x0042:
1502  return 0x42; // LATIN CAPITAL LETTER B
1503  case 0x0043:
1504  return 0x43; // LATIN CAPITAL LETTER C
1505  case 0x0044:
1506  return 0x44; // LATIN CAPITAL LETTER D
1507  case 0x0045:
1508  return 0x45; // LATIN CAPITAL LETTER E
1509  case 0x0046:
1510  return 0x46; // LATIN CAPITAL LETTER F
1511  case 0x0047:
1512  return 0x47; // LATIN CAPITAL LETTER G
1513  case 0x0048:
1514  return 0x48; // LATIN CAPITAL LETTER H
1515  case 0x0049:
1516  return 0x49; // LATIN CAPITAL LETTER I
1517  case 0x004A:
1518  return 0x4A; // LATIN CAPITAL LETTER J
1519  case 0x004B:
1520  return 0x4B; // LATIN CAPITAL LETTER K
1521  case 0x004C:
1522  return 0x4C; // LATIN CAPITAL LETTER L
1523  case 0x004D:
1524  return 0x4D; // LATIN CAPITAL LETTER M
1525  case 0x004E:
1526  return 0x4E; // LATIN CAPITAL LETTER N
1527  case 0x004F:
1528  return 0x4F; // LATIN CAPITAL LETTER O
1529  case 0x0050:
1530  return 0x50; // LATIN CAPITAL LETTER P
1531  case 0x0051:
1532  return 0x51; // LATIN CAPITAL LETTER Q
1533  case 0x0052:
1534  return 0x52; // LATIN CAPITAL LETTER R
1535  case 0x0053:
1536  return 0x53; // LATIN CAPITAL LETTER S
1537  case 0x0054:
1538  return 0x54; // LATIN CAPITAL LETTER T
1539  case 0x0055:
1540  return 0x55; // LATIN CAPITAL LETTER U
1541  case 0x0056:
1542  return 0x56; // LATIN CAPITAL LETTER V
1543  case 0x0057:
1544  return 0x57; // LATIN CAPITAL LETTER W
1545  case 0x0058:
1546  return 0x58; // LATIN CAPITAL LETTER X
1547  case 0x0059:
1548  return 0x59; // LATIN CAPITAL LETTER Y
1549  case 0x005A:
1550  return 0x5A; // LATIN CAPITAL LETTER Z
1551  case 0x253C:
1552  return 0x5B; // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
1553  case 0x1FB8C:
1554  return 0x5C; // LEFT HALF MEDIUM SHADE
1555  case 0x2502:
1556  return 0x5D; // BOX DRAWINGS LIGHT VERTICAL
1557  case 0x1FB95:
1558  return 0x5E; // CHECKER BOARD FILL
1559  case 0x1FB98:
1560  return 0x5F; // UPPER LEFT TO LOWER RIGHT FILL
1561  case 0x00A0:
1562  return 0x60; // NO-BREAK SPACE
1563  case 0x258C:
1564  return 0x61; // LEFT HALF BLOCK
1565  case 0x2584:
1566  return 0x62; // LOWER HALF BLOCK
1567  case 0x2594:
1568  return 0x63; // UPPER ONE EIGHTH BLOCK
1569  case 0x2581:
1570  return 0x64; // LOWER ONE EIGHTH BLOCK
1571  case 0x258F:
1572  return 0x65; // LEFT ONE EIGHTH BLOCK
1573  case 0x2592:
1574  return 0x66; // MEDIUM SHADE
1575  case 0x2595:
1576  return 0x67; // RIGHT ONE EIGHTH BLOCK
1577  case 0x1FB8F:
1578  return 0x68; // LOWER HALF MEDIUM SHADE
1579  case 0x1FB99:
1580  return 0x69; // UPPER RIGHT TO LOWER LEFT FILL
1581  case 0x1FB87:
1582  return 0x6A; // RIGHT ONE QUARTER BLOCK
1583  case 0x251C:
1584  return 0x6B; // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
1585  case 0x2597:
1586  return 0x6C; // QUADRANT LOWER RIGHT
1587  case 0x2514:
1588  return 0x6D; // BOX DRAWINGS LIGHT UP AND RIGHT
1589  case 0x2510:
1590  return 0x6E; // BOX DRAWINGS LIGHT DOWN AND LEFT
1591  case 0x2582:
1592  return 0x6F; // LOWER ONE QUARTER BLOCK
1593  case 0x250C:
1594  return 0x70; // BOX DRAWINGS LIGHT DOWN AND RIGHT
1595  case 0x2534:
1596  return 0x71; // BOX DRAWINGS LIGHT UP AND HORIZONTAL
1597  case 0x252C:
1598  return 0x72; // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
1599  case 0x2524:
1600  return 0x73; // BOX DRAWINGS LIGHT VERTICAL AND LEFT
1601  case 0x258E:
1602  return 0x74; // LEFT ONE QUARTER BLOCK
1603  case 0x258D:
1604  return 0x75; // LEFT THREE EIGHTHS BLOCK
1605  case 0x1FB88:
1606  return 0x76; // RIGHT THREE EIGHTHS BLOCK
1607  case 0x1FB82:
1608  return 0x77; // UPPER ONE QUARTER BLOCK
1609  case 0x1FB83:
1610  return 0x78; // UPPER THREE EIGHTHS BLOCK
1611  case 0x2583:
1612  return 0x79; // LOWER THREE EIGHTHS BLOCK
1613  case 0x2713:
1614  return 0x7A; // CHECK MARK
1615  case 0x2596:
1616  return 0x7B; // QUADRANT LOWER LEFT
1617  case 0x259D:
1618  return 0x7C; // QUADRANT UPPER RIGHT
1619  case 0x2518:
1620  return 0x7D; // BOX DRAWINGS LIGHT UP AND LEFT
1621  case 0x2598:
1622  return 0x7E; // QUADRANT UPPER LEFT
1623  case 0x259A:
1624  return 0x7F; // QUADRANT UPPER LEFT AND LOWER RIGHT
1625  case 0x1FB94:
1626  return 0xDC; // LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK
1627  case 0x1FB96:
1628  return 0xDE; // INVERSE CHECKER BOARD FILL
1629  case 0x2588:
1630  return 0xE0; // FULL BLOCK
1631  case 0x2590:
1632  return 0xE1; // RIGHT HALF BLOCK
1633  case 0x2580:
1634  return 0xE2; // UPPER HALF BLOCK
1635  case 0x2587:
1636  return 0xE3; // LOWER SEVEN EIGHTHS BLOCK
1637  case 0x1FB86:
1638  return 0xE4; // UPPER SEVEN EIGHTHS BLOCK
1639  case 0x1FB8B:
1640  return 0xE5; // RIGHT SEVEN EIGHTHS BLOCK
1641  case 0x1FB90:
1642  return 0xE6; // INVERSE MEDIUM SHADE
1643  case 0x2589:
1644  return 0xE7; // LEFT SEVEN EIGHTHS BLOCK
1645  case 0x1FB91:
1646  return 0xE8; // UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE
1647  case 0x258A:
1648  return 0xEA; // LEFT THREE QUARTERS BLOCK
1649  case 0x259B:
1650  return 0xEC; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT
1651  case 0x1FB85:
1652  return 0xEF; // UPPER THREE QUARTERS BLOCK
1653  case 0x1FB8A:
1654  return 0xF4; // RIGHT THREE QUARTERS BLOCK
1655  case 0x1FB89:
1656  return 0xF5; // RIGHT FIVE EIGHTHS BLOCK
1657  case 0x258B:
1658  return 0xF6; // LEFT FIVE EIGHTHS BLOCK
1659  case 0x2586:
1660  return 0xF7; // LOWER THREE QUARTERS BLOCK
1661  case 0x2585:
1662  return 0xF8; // LOWER FIVE EIGHTHS BLOCK
1663  case 0x1FB84:
1664  return 0xF9; // UPPER FIVE EIGHTHS BLOCK
1665  case 0x1FBB1:
1666  return 0xFA; // INVERSE CHECK MARK
1667  case 0x259C:
1668  return 0xFB; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT
1669  case 0x2599:
1670  return 0xFC; // QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT
1671  case 0x259F:
1672  return 0xFE; // QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
1673  case 0x259E:
1674  return 0xFF; // QUADRANT UPPER RIGHT AND LOWER LEFT
1675  }
1676  }
1677 };
1678 
1679 template <size_t N> struct ShiftedReverseVideoString {
1680  char Str[N]{};
1681 
1682  constexpr ShiftedReverseVideoString(char const (&Src)[N]) {
1683  for (size_t I = 0; I < N; ++I) {
1684  if (Src[I] >= 0x80)
1685  throw "use U prefix for unicode string literals";
1686  Str[I] = TranslateUnicode(Src[I]);
1687  }
1688  }
1689 
1690  constexpr ShiftedReverseVideoString(char16_t const (&Src)[N]) {
1691  for (size_t I = 0; I < N; ++I) {
1692  if (Src[I] >= 0xD800 && Src[I] <= 0xDFFF)
1693  throw "use U prefix for unicode string literals";
1694  Str[I] = TranslateUnicode(Src[I]);
1695  }
1696  }
1697 
1698  constexpr ShiftedReverseVideoString(char32_t const (&Src)[N]) {
1699  for (size_t I = 0; I < N; ++I)
1700  Str[I] = TranslateUnicode(Src[I]);
1701  }
1702 
1703  constexpr char TranslateUnicode(char32_t C) {
1704  switch (C) {
1705  default:
1706  throw "Unsupported";
1707 
1708  // Preserve NUL
1709  case 0x0000:
1710  return 0x00;
1711 
1712  // Name: Map from Commodore 64/128 (video) alternate character set to
1713  // Unicode
1714 
1715  // Date: 2018 October 11
1716 
1717  // Author: Rebecca Bettencourt <support@kreativekorp.com>
1718 
1719  case 0x1FB94:
1720  return 0x5C; // LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK
1721  case 0x1FB96:
1722  return 0x5E; // INVERSE CHECKER BOARD FILL
1723  case 0x2588:
1724  return 0x60; // FULL BLOCK
1725  case 0x2590:
1726  return 0x61; // RIGHT HALF BLOCK
1727  case 0x2580:
1728  return 0x62; // UPPER HALF BLOCK
1729  case 0x2587:
1730  return 0x63; // LOWER SEVEN EIGHTHS BLOCK
1731  case 0x1FB86:
1732  return 0x64; // UPPER SEVEN EIGHTHS BLOCK
1733  case 0x1FB8B:
1734  return 0x65; // RIGHT SEVEN EIGHTHS BLOCK
1735  case 0x1FB90:
1736  return 0x66; // INVERSE MEDIUM SHADE
1737  case 0x2589:
1738  return 0x67; // LEFT SEVEN EIGHTHS BLOCK
1739  case 0x1FB91:
1740  return 0x68; // UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE
1741  case 0x258A:
1742  return 0x6A; // LEFT THREE QUARTERS BLOCK
1743  case 0x259B:
1744  return 0x6C; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT
1745  case 0x1FB85:
1746  return 0x6F; // UPPER THREE QUARTERS BLOCK
1747  case 0x1FB8A:
1748  return 0x74; // RIGHT THREE QUARTERS BLOCK
1749  case 0x1FB89:
1750  return 0x75; // RIGHT FIVE EIGHTHS BLOCK
1751  case 0x258B:
1752  return 0x76; // LEFT FIVE EIGHTHS BLOCK
1753  case 0x2586:
1754  return 0x77; // LOWER THREE QUARTERS BLOCK
1755  case 0x2585:
1756  return 0x78; // LOWER FIVE EIGHTHS BLOCK
1757  case 0x1FB84:
1758  return 0x79; // UPPER FIVE EIGHTHS BLOCK
1759  case 0x1FBB1:
1760  return 0x7A; // INVERSE CHECK MARK
1761  case 0x259C:
1762  return 0x7B; // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT
1763  case 0x2599:
1764  return 0x7C; // QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT
1765  case 0x259F:
1766  return 0x7E; // QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
1767  case 0x259E:
1768  return 0x7F; // QUADRANT UPPER RIGHT AND LOWER LEFT
1769  case 0x0040:
1770  return 0x80; // COMMERCIAL AT
1771  case 0x0061:
1772  return 0x81; // LATIN SMALL LETTER A
1773  case 0x0062:
1774  return 0x82; // LATIN SMALL LETTER B
1775  case 0x0063:
1776  return 0x83; // LATIN SMALL LETTER C
1777  case 0x0064:
1778  return 0x84; // LATIN SMALL LETTER D
1779  case 0x0065:
1780  return 0x85; // LATIN SMALL LETTER E
1781  case 0x0066:
1782  return 0x86; // LATIN SMALL LETTER F
1783  case 0x0067:
1784  return 0x87; // LATIN SMALL LETTER G
1785  case 0x0068:
1786  return 0x88; // LATIN SMALL LETTER H
1787  case 0x0069:
1788  return 0x89; // LATIN SMALL LETTER I
1789  case 0x006A:
1790  return 0x8A; // LATIN SMALL LETTER J
1791  case 0x006B:
1792  return 0x8B; // LATIN SMALL LETTER K
1793  case 0x006C:
1794  return 0x8C; // LATIN SMALL LETTER L
1795  case 0x006D:
1796  return 0x8D; // LATIN SMALL LETTER M
1797  case 0x006E:
1798  return 0x8E; // LATIN SMALL LETTER N
1799  case 0x006F:
1800  return 0x8F; // LATIN SMALL LETTER O
1801  case 0x0070:
1802  return 0x90; // LATIN SMALL LETTER P
1803  case 0x0071:
1804  return 0x91; // LATIN SMALL LETTER Q
1805  case 0x0072:
1806  return 0x92; // LATIN SMALL LETTER R
1807  case 0x0073:
1808  return 0x93; // LATIN SMALL LETTER S
1809  case 0x0074:
1810  return 0x94; // LATIN SMALL LETTER T
1811  case 0x0075:
1812  return 0x95; // LATIN SMALL LETTER U
1813  case 0x0076:
1814  return 0x96; // LATIN SMALL LETTER V
1815  case 0x0077:
1816  return 0x97; // LATIN SMALL LETTER W
1817  case 0x0078:
1818  return 0x98; // LATIN SMALL LETTER X
1819  case 0x0079:
1820  return 0x99; // LATIN SMALL LETTER Y
1821  case 0x007A:
1822  return 0x9A; // LATIN SMALL LETTER Z
1823  case 0x005B:
1824  return 0x9B; // LEFT SQUARE BRACKET
1825  case 0x005C:
1826  return 0x9C; // REVERSE SOLIDUS
1827  case 0x005D:
1828  return 0x9D; // RIGHT SQUARE BRACKET
1829  case 0x2191:
1830  return 0x9E; // UPWARDS ARROW
1831  case 0x2190:
1832  return 0x9F; // LEFTWARDS ARROW
1833  case 0x0020:
1834  return 0xA0; // SPACE
1835  case 0x0021:
1836  return 0xA1; // EXCLAMATION MARK
1837  case 0x0022:
1838  return 0xA2; // QUOTATION MARK
1839  case 0x0023:
1840  return 0xA3; // NUMBER SIGN
1841  case 0x0024:
1842  return 0xA4; // DOLLAR SIGN
1843  case 0x0025:
1844  return 0xA5; // PERCENT SIGN
1845  case 0x0026:
1846  return 0xA6; // AMPERSAND
1847  case 0x0027:
1848  return 0xA7; // APOSTROPHE
1849  case 0x0028:
1850  return 0xA8; // LEFT PARENTHESIS
1851  case 0x0029:
1852  return 0xA9; // RIGHT PARENTHESIS
1853  case 0x002A:
1854  return 0xAA; // ASTERISK
1855  case 0x002B:
1856  return 0xAB; // PLUS SIGN
1857  case 0x002C:
1858  return 0xAC; // COMMA
1859  case 0x002D:
1860  return 0xAD; // HYPHEN-MINUS
1861  case 0x002E:
1862  return 0xAE; // FULL STOP
1863  case 0x002F:
1864  return 0xAF; // SOLIDUS
1865  case 0x0030:
1866  return 0xB0; // DIGIT ZERO
1867  case 0x0031:
1868  return 0xB1; // DIGIT ONE
1869  case 0x0032:
1870  return 0xB2; // DIGIT TWO
1871  case 0x0033:
1872  return 0xB3; // DIGIT THREE
1873  case 0x0034:
1874  return 0xB4; // DIGIT FOUR
1875  case 0x0035:
1876  return 0xB5; // DIGIT FIVE
1877  case 0x0036:
1878  return 0xB6; // DIGIT SIX
1879  case 0x0037:
1880  return 0xB7; // DIGIT SEVEN
1881  case 0x0038:
1882  return 0xB8; // DIGIT EIGHT
1883  case 0x0039:
1884  return 0xB9; // DIGIT NINE
1885  case 0x003A:
1886  return 0xBA; // COLON
1887  case 0x003B:
1888  return 0xBB; // SEMICOLON
1889  case 0x003C:
1890  return 0xBC; // LESS-THAN SIGN
1891  case 0x003D:
1892  return 0xBD; // EQUALS SIGN
1893  case 0x003E:
1894  return 0xBE; // GREATER-THAN SIGN
1895  case 0x003F:
1896  return 0xBF; // QUESTION MARK
1897  case 0x2500:
1898  return 0xC0; // BOX DRAWINGS LIGHT HORIZONTAL
1899  case 0x0041:
1900  return 0xC1; // LATIN CAPITAL LETTER A
1901  case 0x0042:
1902  return 0xC2; // LATIN CAPITAL LETTER B
1903  case 0x0043:
1904  return 0xC3; // LATIN CAPITAL LETTER C
1905  case 0x0044:
1906  return 0xC4; // LATIN CAPITAL LETTER D
1907  case 0x0045:
1908  return 0xC5; // LATIN CAPITAL LETTER E
1909  case 0x0046:
1910  return 0xC6; // LATIN CAPITAL LETTER F
1911  case 0x0047:
1912  return 0xC7; // LATIN CAPITAL LETTER G
1913  case 0x0048:
1914  return 0xC8; // LATIN CAPITAL LETTER H
1915  case 0x0049:
1916  return 0xC9; // LATIN CAPITAL LETTER I
1917  case 0x004A:
1918  return 0xCA; // LATIN CAPITAL LETTER J
1919  case 0x004B:
1920  return 0xCB; // LATIN CAPITAL LETTER K
1921  case 0x004C:
1922  return 0xCC; // LATIN CAPITAL LETTER L
1923  case 0x004D:
1924  return 0xCD; // LATIN CAPITAL LETTER M
1925  case 0x004E:
1926  return 0xCE; // LATIN CAPITAL LETTER N
1927  case 0x004F:
1928  return 0xCF; // LATIN CAPITAL LETTER O
1929  case 0x0050:
1930  return 0xD0; // LATIN CAPITAL LETTER P
1931  case 0x0051:
1932  return 0xD1; // LATIN CAPITAL LETTER Q
1933  case 0x0052:
1934  return 0xD2; // LATIN CAPITAL LETTER R
1935  case 0x0053:
1936  return 0xD3; // LATIN CAPITAL LETTER S
1937  case 0x0054:
1938  return 0xD4; // LATIN CAPITAL LETTER T
1939  case 0x0055:
1940  return 0xD5; // LATIN CAPITAL LETTER U
1941  case 0x0056:
1942  return 0xD6; // LATIN CAPITAL LETTER V
1943  case 0x0057:
1944  return 0xD7; // LATIN CAPITAL LETTER W
1945  case 0x0058:
1946  return 0xD8; // LATIN CAPITAL LETTER X
1947  case 0x0059:
1948  return 0xD9; // LATIN CAPITAL LETTER Y
1949  case 0x005A:
1950  return 0xDA; // LATIN CAPITAL LETTER Z
1951  case 0x253C:
1952  return 0xDB; // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
1953  case 0x1FB8C:
1954  return 0xDC; // LEFT HALF MEDIUM SHADE
1955  case 0x2502:
1956  return 0xDD; // BOX DRAWINGS LIGHT VERTICAL
1957  case 0x1FB95:
1958  return 0xDE; // CHECKER BOARD FILL
1959  case 0x1FB98:
1960  return 0xDF; // UPPER LEFT TO LOWER RIGHT FILL
1961  case 0x00A0:
1962  return 0xE0; // NO-BREAK SPACE
1963  case 0x258C:
1964  return 0xE1; // LEFT HALF BLOCK
1965  case 0x2584:
1966  return 0xE2; // LOWER HALF BLOCK
1967  case 0x2594:
1968  return 0xE3; // UPPER ONE EIGHTH BLOCK
1969  case 0x2581:
1970  return 0xE4; // LOWER ONE EIGHTH BLOCK
1971  case 0x258F:
1972  return 0xE5; // LEFT ONE EIGHTH BLOCK
1973  case 0x2592:
1974  return 0xE6; // MEDIUM SHADE
1975  case 0x2595:
1976  return 0xE7; // RIGHT ONE EIGHTH BLOCK
1977  case 0x1FB8F:
1978  return 0xE8; // LOWER HALF MEDIUM SHADE
1979  case 0x1FB99:
1980  return 0xE9; // UPPER RIGHT TO LOWER LEFT FILL
1981  case 0x1FB87:
1982  return 0xEA; // RIGHT ONE QUARTER BLOCK
1983  case 0x251C:
1984  return 0xEB; // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
1985  case 0x2597:
1986  return 0xEC; // QUADRANT LOWER RIGHT
1987  case 0x2514:
1988  return 0xED; // BOX DRAWINGS LIGHT UP AND RIGHT
1989  case 0x2510:
1990  return 0xEE; // BOX DRAWINGS LIGHT DOWN AND LEFT
1991  case 0x2582:
1992  return 0xEF; // LOWER ONE QUARTER BLOCK
1993  case 0x250C:
1994  return 0xF0; // BOX DRAWINGS LIGHT DOWN AND RIGHT
1995  case 0x2534:
1996  return 0xF1; // BOX DRAWINGS LIGHT UP AND HORIZONTAL
1997  case 0x252C:
1998  return 0xF2; // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
1999  case 0x2524:
2000  return 0xF3; // BOX DRAWINGS LIGHT VERTICAL AND LEFT
2001  case 0x258E:
2002  return 0xF4; // LEFT ONE QUARTER BLOCK
2003  case 0x258D:
2004  return 0xF5; // LEFT THREE EIGHTHS BLOCK
2005  case 0x1FB88:
2006  return 0xF6; // RIGHT THREE EIGHTHS BLOCK
2007  case 0x1FB82:
2008  return 0xF7; // UPPER ONE QUARTER BLOCK
2009  case 0x1FB83:
2010  return 0xF8; // UPPER THREE EIGHTHS BLOCK
2011  case 0x2583:
2012  return 0xF9; // LOWER THREE EIGHTHS BLOCK
2013  case 0x2713:
2014  return 0xFA; // CHECK MARK
2015  case 0x2596:
2016  return 0xFB; // QUADRANT LOWER LEFT
2017  case 0x259D:
2018  return 0xFC; // QUADRANT UPPER RIGHT
2019  case 0x2518:
2020  return 0xFD; // BOX DRAWINGS LIGHT UP AND LEFT
2021  case 0x2598:
2022  return 0xFE; // QUADRANT UPPER LEFT
2023  case 0x259A:
2024  return 0xFF; // QUADRANT UPPER LEFT AND LOWER RIGHT
2025  }
2026  }
2027 };
2028 
2029 } // namespace charset_impl
2030 
2031 template <charset_impl::UnshiftedString S> constexpr auto operator""_u() {
2032  return S.Str;
2033 }
2034 
2035 template <charset_impl::ShiftedString S> constexpr auto operator""_s() {
2036  return S.Str;
2037 }
2038 
2039 template <charset_impl::UnshiftedVideoString S> constexpr auto operator""_uv() {
2040  return S.Str;
2041 }
2042 
2043 template <charset_impl::UnshiftedReverseVideoString S>
2044 constexpr auto operator""_urv() {
2045  return S.Str;
2046 }
2047 
2048 template <charset_impl::ShiftedVideoString S> constexpr auto operator""_sv() {
2049  return S.Str;
2050 }
2051 
2052 template <charset_impl::ShiftedReverseVideoString S>
2053 constexpr auto operator""_srv() {
2054  return S.Str;
2055 }
2056 
2057 #endif // not _CHARSET_H
2058 #endif // __cplusplus >= 202002L
cstddef