Better test output on Xterm

pull/198/head
Martin D Kealey 2 years ago
parent 49a66a2b8b
commit 4ec74454ac

@ -39,9 +39,126 @@ static void doSegmentDemo(void);
static void doMaskDemo(void);
static void printQr(const uint8_t qrcode[]);
static int border = 4;
typedef struct output_formatting {
char const *begin_code;
char const *begin_line;
char const *light;
char const *dark;
char const *same;
char const *end_line;
char const *end_code;
bool braille_map;
uint32_t *charMap;
int num_across;
int num_down;
} OFM;
typedef enum {
blackOnWhite,
whiteOnBlack,
ansiColour,
unicodeHalfBlock,
unicodeBraille,
} TermMode;
static TermMode outputMode = blackOnWhite;
static OFM ofmt[] = {
[blackOnWhite] = (OFM){
/* this assumes dark text on light background */
.light = " ",
.dark = "##",
},
[whiteOnBlack] = (OFM){
/* this assumes light text on dark background */
.light = "##",
.dark = " ",
},
[ansiColour] = (OFM){
.begin_line = "",
.light = "\033[47m ",
.dark = "\033[40m ",
.same = " ",
.end_line = "\033[m\n",
},
[unicodeHalfBlock] = (OFM){
.begin_line = "\033[30;47m",
.end_line = "\033[39;49m\n",
.num_across = 1,
.num_down = 2,
.charMap = (uint32_t[4]){
' ', /* clear bottom & top */
0x2580, /* ▀ clear bottom, marked top */
0x2584, /* ▄ marked bottom, clear top */
0x2588, /* █ marked bottom & top */
},
},
[unicodeBraille] = (OFM){
.begin_line = "\033[30;47m",
.end_line = "\033[39;49m\n",
.braille_map = true,
.num_across = 2,
.num_down = 4,
},
};
// The main application program.
int main(void) {
int main(int argc/*unused*/, char const*const*argv) {
char const*argv0 = *argv++;
for (;;) {
char const*arg = *argv++;
if (!arg || *arg++ != '-') break; /* "-" as a non-option arg */
char opt = *arg++;
if (!opt) { --argv; break; }
if (opt == '-') {
if (!*arg) break; /* "--" marks end of options */
if (!strcmp(arg, "border" )) opt = 'b';
else if (!strcmp(arg, "plain" )) opt = 'p';
else if (!strcmp(arg, "plain=bow")) opt = 'p';
else if (!strcmp(arg, "plain=wob")) opt = 'P';
else if (!strcmp(arg, "unicode=braille")) opt = 'Q';
else if (!strcmp(arg, "unicode=halfblock")) opt = 'R';
else if (!strcmp(arg, "ansi" )) opt = 'S';
else goto bad_opt;
arg = NULL;
}
switch (opt) {
case 'P': outputMode = blackOnWhite; break;
case 'Q': outputMode = unicodeBraille; break;
case 'R': outputMode = unicodeHalfBlock; break;
case 'S': outputMode = ansiColour; break;
case 'p': outputMode = whiteOnBlack; break;
case 'b': arg = arg && *arg ? arg : *argv++;
if (!arg) goto missing_value;
border = strtol(arg, (char**)&arg, 10);
if (*arg) goto bad_value;
arg = NULL;
break;
default: goto bad_opt;
}
if (arg && *arg) {
fprintf(stderr, "Bundled options not supported at '%s'\n", arg);
return EXIT_FAILURE;
}
continue;
bad_opt:
fprintf(stderr, "Invalid option '%s'\n", argv[-1]);
return EXIT_FAILURE;
missing_value:
fprintf(stderr, "Missing value for option '%s'\n", argv[-1]);
return EXIT_FAILURE;
bad_value:
fprintf(stderr, "Improper numeric value '%s'\n", argv[-1]);
return EXIT_FAILURE;
}
doBasicDemo();
doVarietyDemo();
doSegmentDemo();
@ -321,15 +438,79 @@ static void doMaskDemo(void) {
/*---- Utilities ----*/
static inline void wputchar(uint32_t ch) {
if (ch < 0x80)
putchar(ch);
else if (ch < 0x800)
putchar(0xc0 | ch >> 6 & 0x1f),
putchar(0x80 | ch & 0x3f);
else if (ch < 0x10000)
putchar(0xe0 | ch >> 12 & 0x0f),
putchar(0x80 | ch >> 6 & 0x3f),
putchar(0x80 | ch & 0x3f);
else if (ch < 0x200000)
putchar(0xf0 | ch >> 18 & 0x07),
putchar(0x80 | ch >> 12 & 0x3f),
putchar(0x80 | ch >> 6 & 0x3f),
putchar(0x80 | ch & 0x3f);
else
putchar('?');
}
// Prints the given QR Code to the console.
static void printQr(const uint8_t qrcode[]) {
int size = qrcodegen_getSize(qrcode);
int border = 4;
struct output_formatting *of = &ofmt[outputMode];
if (of->begin_code)
fputs(of->begin_code, stdout);
int const num_across = of->num_across;
int const num_down = of->num_down;
if (num_across && num_down)
for (int y = -border; y < size + border; y += num_down) {
if (of->begin_line)
fputs(of->begin_line, stdout);
for (int x = -border; x < size + border; x += num_across) {
uint32_t cellBits = 0;
for (int dx = num_across; dx-- > 0;) {
for (int dy = num_down; dy-- > 0;) {
cellBits <<= 1;
bool bit = qrcodegen_getModule(qrcode, x+dx, y+dy);
cellBits |= bit;
}
}
wchar_t cellChar = '?';
if (of->braille_map) {
/*
* cellChar Braille
* 0 4 must be 0 3
* 1 5 rearranged to 1 4
* 2 6 this order 2 5
* 3 7 6 7
*/
cellChar = cellBits & 0x87
| cellBits << 3 & 0x40
| cellBits >> 1 & 0x38
| 0x2800; /* start of Braille range in Unicode */
} else if (of->charMap)
cellChar = of->charMap[cellBits];
else
cellChar = cellBits;
wputchar(cellChar);
}
fputs(of->end_line ?: "\n", stdout);
}
else
for (int y = -border; y < size + border; y++) {
int prevBit = -1; /* neither true nor false */
if (of->begin_line)
fputs(of->begin_line, stdout);
for (int x = -border; x < size + border; x++) {
fputs((qrcodegen_getModule(qrcode, x, y) ? "##" : " "), stdout);
bool thisBit = qrcodegen_getModule(qrcode, x, y);
fputs( ! of->same || prevBit != thisBit ? thisBit ? of->dark : of->light : of->same,
stdout );
prevBit = thisBit;
}
fputs("\n", stdout);
fputs(of->end_line ?: "\n", stdout);
}
fputs("\n", stdout);
fputs(of->end_code ?: "\n", stdout);
}

Loading…
Cancel
Save