Better test output on Xterm

pull/198/head
Martin D Kealey 1 year ago
parent 49a66a2b8b
commit 4ec74454ac

@ -1,12 +1,12 @@
/*
/*
* QR Code generator demo (C)
*
*
* Run this command-line program with no arguments. The program
* computes a demonstration QR Codes and print it to the console.
*
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
@ -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();
@ -57,7 +174,7 @@ int main(void) {
static void doBasicDemo(void) {
const char *text = "Hello, world!"; // User-supplied text
enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW; // Error correction level
// Make and print the QR Code symbol
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
@ -78,7 +195,7 @@ static void doVarietyDemo(void) {
if (ok)
printQr(qrcode);
}
{ // Alphanumeric mode encoding (5.5 bits per character)
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
@ -87,7 +204,7 @@ static void doVarietyDemo(void) {
if (ok)
printQr(qrcode);
}
{ // Unicode text as UTF-8
const char *text = "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81"
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4";
@ -98,7 +215,7 @@ static void doVarietyDemo(void) {
if (ok)
printQr(qrcode);
}
{ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
const char *text =
"Alice was beginning to get very tired of sitting by her sister on the bank, "
@ -158,7 +275,7 @@ static void doSegmentDemo(void) {
printQr(qrcode);
}
}
{ // Illustration "golden"
const char *golden0 = "Golden ratio \xCF\x86 = 1.";
const char *golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
@ -210,7 +327,7 @@ static void doSegmentDemo(void) {
printQr(qrcode);
}
}
{ // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
@ -270,18 +387,18 @@ static void doMaskDemo(void) {
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_3, true);
if (ok)
printQr(qrcode);
}
{ // Chinese text as UTF-8
const char *text =
"\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70"
@ -294,22 +411,22 @@ static void doMaskDemo(void) {
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_0, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_1, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_5, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_7, true);
if (ok)
@ -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;
for (int y = -border; y < size + border; y++) {
for (int x = -border; x < size + border; x++) {
fputs((qrcodegen_getModule(qrcode, x, y) ? "##" : " "), stdout);
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);
}
fputs("\n", stdout);
}
fputs("\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++) {
bool thisBit = qrcodegen_getModule(qrcode, x, y);
fputs( ! of->same || prevBit != thisBit ? thisBit ? of->dark : of->light : of->same,
stdout );
prevBit = thisBit;
}
fputs(of->end_line ?: "\n", stdout);
}
fputs(of->end_code ?: "\n", stdout);
}

Loading…
Cancel
Save