From 9db7f77f12a754e486c8125c533842b0698735fe Mon Sep 17 00:00:00 2001 From: Sunshine Date: Mon, 18 Oct 2021 20:37:07 -1000 Subject: [PATCH 1/3] make possible to generate animated QR codes --- Dockerfile | 2 +- Makefile | 2 +- README.md | 23 +- config.mk | 2 +- utils/qr.sh => dist/run-in-container.sh | 2 +- qr.c | 328 ++++++++++++++++-------- tests.at | 20 +- 7 files changed, 253 insertions(+), 126 deletions(-) rename utils/qr.sh => dist/run-in-container.sh (73%) diff --git a/Dockerfile b/Dockerfile index 46a83ac..1b72e59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN apk update && \ COPY Makefile qr.c . RUN make clean && \ - make -j 16 && \ + make -j && \ make install CMD ["qr"] diff --git a/Makefile b/Makefile index 0e1dfc0..771aef3 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ include config.mk $(PROG): - $(CC) $(PROG).c $(CFLAGS) $(LIBS) -DVERSION="\"$(VERSION)\"" -o $(PROG) + $(CC) $(PROG).c $(CFLAGS) $(LIBS) -DPROG="\"$(PROG)\"" -DVERSION="\"$(VERSION)\"" -o $(PROG) all: $(PROG) .PHONY: all diff --git a/README.md b/README.md index da121ce..b0e0cd0 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,7 @@ Print Unicode-friendly QR Codes® straight in your terminal! $ make -
- Build dependencies -
+#### Build dependencies - [libqrencode](https://github.com/fukuchi/libqrencode) ###### Resolve on Ubuntu or Debian @@ -24,8 +22,6 @@ Print Unicode-friendly QR Codes® straight in your terminal! $ make # make install -
- ## How to install @@ -37,8 +33,8 @@ or ## How to build and install using containers - $ docker build -t y2z/qr . - $ sudo install -b utils/qr.sh /usr/local/bin/qr + $ docker build -t Y2Z/qr . + $ sudo install -b dist/run-in-container.sh /usr/local/bin/qr ## How to build and install on FreeBSD @@ -56,13 +52,17 @@ or or $ echo -n "Hello" | qr +or + + $ cat file.png | qr -a #### Options - Usage: qr [OPTIONS] STRING + Usage: qr [OPTIONS] [STRING] or: cat FILE | qr [OPTIONS] Options: + -a produce animated QR code -m QR mode [na8k] (n = number, a = alphabet, 8 = 8-bit, k = Kanji) -v QR version [1-40] -e QR EC level [lmqh] or [1-4] @@ -71,6 +71,7 @@ or -b border width [1-4] (the default is 1) -i invert colors -p force colorless output + -u ensure output has UTF-8 BOM -h print help info and exit -V print version info and exit @@ -84,9 +85,7 @@ or $ make test -
- Test dependencies -
+#### Test dependencies - [autoconf](https://www.gnu.org/software/autoconf/autoconf.html) ###### Resolve on Ubuntu or Debian @@ -110,8 +109,6 @@ or $ brew tap homebrew/cask-fonts $ brew install --cask font-freefont -
- ## Acknowledgements diff --git a/config.mk b/config.mk index 77f58fa..a74abc3 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # qr version -VERSION = 1.0.0 +VERSION = 2.0.0 # program name PROG = qr diff --git a/utils/qr.sh b/dist/run-in-container.sh similarity index 73% rename from utils/qr.sh rename to dist/run-in-container.sh index bf495e6..5ce8c76 100755 --- a/utils/qr.sh +++ b/dist/run-in-container.sh @@ -6,4 +6,4 @@ if which podman 2>&1 > /dev/null; then DOCKER=podman fi -$DOCKER run --rm y2z/qr qr "$@" +$DOCKER run --rm Y2Z/qr qr "$@" diff --git a/qr.c b/qr.c index 61c4dea..e65cc9a 100644 --- a/qr.c +++ b/qr.c @@ -13,9 +13,10 @@ #include #include #include +#include #include -/* STDIN read buffer chunk size */ +/* STDIN read buffer chunk size in bytes */ #define STDIN_CHUNKSIZE 64 /* Single-module blocks (large size) */ @@ -61,8 +62,9 @@ #define BGBK_FGWH BG_BK FG_WH #define BGDF_FGDF BG_DF FG_DF -/* Newline character(s) */ +/* Characters used in terminal output */ #define EOL "\n" +#define CLR "\033[A\33[2KT\r" typedef unsigned char bool; #define true 1 @@ -93,6 +95,7 @@ typedef unsigned char bool; #define B_1111 15 typedef struct { + bool anim; char encode_mode; int version; char ec_level; @@ -101,6 +104,7 @@ typedef struct { short border; bool invert; bool plain; + bool unicode; } Options; /* Unicode BOM */ @@ -108,19 +112,21 @@ const char *utf8_bom = "\xEF\xBB\xBF"; /* Help message */ const char *help_msg = - "Usage: qr [OPTIONS] STRING" EOL - " or: cat FILE | qr [OPTIONS]" EOL + "Usage: " PROG " [OPTIONS] [STRING]" EOL + " or: cat FILE | " PROG " [OPTIONS]" EOL EOL "Options:" EOL + " -a produce animated QR code" EOL " -m QR mode [na8k] (n = number, a = alphabet, 8 = 8-bit, " "k = Kanji)" EOL " -v QR version [1-40]" EOL " -e QR EC level [lmqh] or [1-4]" EOL - " -l use two characters per block" EOL + " -l large mode" EOL " -c compact mode" EOL " -b border width [1-4] (the default is 1)" EOL " -i invert colors" EOL " -p force colorless output" EOL + " -u ensure output has UTF-8 BOM" EOL " -h print help info and exit" EOL " -V print version info and exit" EOL ; @@ -132,7 +138,7 @@ void print_help_msg(void) void print_version(void) { - printf("qr %s" EOL, VERSION); + printf(PROG " %s" EOL, VERSION); } void print_error(const char *message) @@ -140,7 +146,15 @@ void print_error(const char *message) fprintf(stderr, "Error: %s" EOL, message); } -static inline bool str_has_utf8_bom(const char *string) +void msleep(const int ms) +{ + struct timeval tv; + tv.tv_sec = ms / 1000; + tv.tv_usec = (ms % 1000) * 1000; + select(0, NULL, NULL, NULL, &tv); +} + +static inline bool is_utf8_string(const char *string) { return (strcmp(string, utf8_bom) == 0); } @@ -155,6 +169,7 @@ char *qr_data_to_text(const QRcode *code, const char border_width, const unsigned char *data = code->data; if (data == NULL) { + print_error("empty QR code data"); return NULL; } @@ -164,9 +179,11 @@ char *qr_data_to_text(const QRcode *code, const char border_width, char *text; if (large_size) { - /*******************************************************************/ - /* One module per block (large size and large size + compact mode) */ - /*******************************************************************/ + /*********************************************************************/ + /* */ + /* One module per block (large size and large size + compact mode) */ + /* */ + /*********************************************************************/ const char *blocks[2] = { // 0 @@ -261,14 +278,18 @@ char *qr_data_to_text(const QRcode *code, const char border_width, strcat(text, EOL); } } else { - /****************************************************************/ - /* Two or four modules per block (normal mode and compact mode) */ - /****************************************************************/ + /******************************************************************/ + /* */ + /* Two or four modules per block (normal mode and compact mode) */ + /* */ + /******************************************************************/ if (compact_mode) { - /*****************************************/ - /* Four modules per block (compact mode) */ - /*****************************************/ + /*******************************************/ + /* */ + /* Four modules per block (compact mode) */ + /* */ + /*******************************************/ const char *blocks[16] = { (invert_colors) ? QUAD_BLOCK_0000 : QUAD_BLOCK_1111, @@ -493,9 +514,11 @@ char *qr_data_to_text(const QRcode *code, const char border_width, strcat(text, EOL); } } else { - /***************************************/ - /* Two modules per block (normal mode) */ - /***************************************/ + /*****************************************/ + /* */ + /* Two modules per block (normal mode) */ + /* */ + /*****************************************/ const char *blocks[4] = { (invert_colors) ? DBL_BLOCK_00 : DBL_BLOCK_11, @@ -688,9 +711,11 @@ QRecLevel get_qr_ec_level(const char ec_level) int main(int argc, char *argv[]) { - int ret = 0; + int ret = 0, c = 0; char *str = NULL; - int c = 0; + // bool str_is_dynmically_allocated = false; + const bool is_stdin_input = !isatty(STDIN_FILENO); + const bool is_term_output = isatty(STDOUT_FILENO); // Enable wide-character support char *p = setlocale(LC_ALL, ""); @@ -700,6 +725,7 @@ int main(int argc, char *argv[]) /* Default options */ Options options = { + .anim = false, .encode_mode = '8', .version = 0, .ec_level = '1', @@ -707,38 +733,18 @@ int main(int argc, char *argv[]) .compact = false, .border = 1, .invert = false, - .plain = false + .plain = false, + .unicode = false, }; - /* Process STDIN (if any) */ - if (!isatty(STDIN_FILENO)) { - size_t bufsize = STDIN_CHUNKSIZE; - str = malloc(bufsize); - ssize_t stdin_read_size = 0; - size_t total_bytes = 0; - - while ((stdin_read_size = read(STDIN_FILENO, str, STDIN_CHUNKSIZE)) > 0) { - total_bytes += stdin_read_size; - bufsize += STDIN_CHUNKSIZE; - str = realloc(str, bufsize); - - if (str == NULL) { - print_error("out of memory"); - ret = 1; - goto exit; - } - } - } - - /* Parse CLI arguments */ - while (optind < argc) { - if ((c = getopt(argc, argv, "m:v:e:lcb:iphV")) == -1) { - free(str); - str = argv[optind++]; - continue; - } - + /* Parse CLI flags and options */ + while ((c = getopt(argc, argv, "am:v:e:lcb:ipuhV")) != -1) { switch (c) { + break; + case 'a': + options.anim = true; + break; + case 'm': options.encode_mode = optarg[0]; break; @@ -771,6 +777,10 @@ int main(int argc, char *argv[]) options.plain = true; break; + case 'u': + options.unicode = true; + break; + case '?': ret = 1; goto exit; @@ -785,7 +795,25 @@ int main(int argc, char *argv[]) } } - /* Validate options */ + /* Validate and process CLI arguments */ + while (optind < argc) { + if (argc - optind > 1) { + print_error("too many arguments"); + fprintf(stderr, "%s" EOL, help_msg); + ret = 1; + goto exit; + } + + // Ignore input provided via CLI when STDIN is available + if (!is_stdin_input) { + str = realloc(str, strlen(argv[optind]) + 1); + strcpy(str, argv[optind]); + } + + optind++; + } + + /* Validate given options */ if ( options.version < 0 || options.version > QRSPEC_VERSION_MAX || get_qr_ec_level(options.ec_level) < 0 || @@ -798,17 +826,28 @@ int main(int argc, char *argv[]) goto exit; } - /* Validate arguments */ - if (optind != argc) { + /* Process STDIN (if any) */ + if (is_stdin_input) { + size_t buf_size = STDIN_CHUNKSIZE; + char buf[buf_size]; if (str != NULL) { - print_error("too many arguments"); - fprintf(stderr, "%s" EOL, help_msg); - ret = 1; - goto exit; + free(str); } + str = NULL; + ssize_t stdin_read_size = 0; + size_t total_bytes = 0; - str = malloc(strlen(argv[optind])+1); - memcpy(&str, &argv[optind], strlen(argv[optind])+1); + while ((stdin_read_size = read(STDIN_FILENO, buf, STDIN_CHUNKSIZE)) > 0) { + str = realloc(str, total_bytes + stdin_read_size + 1); + if (str == NULL) { + print_error("out of memory"); + ret = 1; + goto exit; + } + memcpy(&str[total_bytes], buf, stdin_read_size); + total_bytes += stdin_read_size; + } + str[total_bytes] = '\0'; } /* Check input */ @@ -819,58 +858,143 @@ int main(int argc, char *argv[]) goto exit; } - /*******************************/ - /* Generate and output QR code */ - /*******************************/ - - QRcode *qr; - - /* Ensure QR Code contains UTF-8 BOM */ - if (str_has_utf8_bom(str)) { - qr = QRcode_encodeString(str, options.version, - get_qr_ec_level(options.ec_level), - get_qr_encode_mode(options.encode_mode), true); - } else { - char str_utf8[strlen(utf8_bom) + strlen(str) + 1]; - memset(str_utf8, '\0', sizeof(str_utf8)); - strncpy(str_utf8, utf8_bom, sizeof(str_utf8)); - strncat(str_utf8, str, sizeof(str_utf8)); - str_utf8[strlen(utf8_bom) + strlen(str)] = '\0'; - qr = QRcode_encodeString(str_utf8, options.version, - get_qr_ec_level(options.ec_level), - get_qr_encode_mode(options.encode_mode), true); - } - - /* Bail out if unable to successfully execute QRcode_encodeString() */ - if (qr == NULL) { - print_error("failed to generate QR code"); - ret = 1; - goto exit; - } - /* Enforce colorless output mode for non-terminal environments */ - if (!isatty(STDOUT_FILENO)) { + if (!is_term_output) { options.plain = true; } - /* Convert QR code data into text */ - char *qr_code_text = qr_data_to_text(qr, options.border, options.invert, - !options.plain, options.large, - options.compact); + /* Ensure that input string contains UTF-8 BOM */ + if (options.unicode && !is_utf8_string(str)) { + /* Prepend UTF-8 BOM */ + str = realloc(str, strlen(utf8_bom) + strlen(str) + 1); + memmove(str + strlen(utf8_bom), str, strlen(str) + 1); + memcpy(str, utf8_bom, strlen(utf8_bom)); + } + + /*********************************/ + /* */ + /* Generate and output QR code */ + /* */ + /*********************************/ + + if (options.anim) { + // Determine amount of chunks (frames) + const int data_chunk_size = 100; // Max chunk size in bytes + size_t data_chunk_count = strlen(str) / data_chunk_size; + // Account for leftover error (if any) + if (data_chunk_count * data_chunk_size < strlen(str)) { + data_chunk_count++; + } + unsigned char data_chunk[data_chunk_size + 1]; + + while (true) { + for (size_t str_chunk_i = 0; str_chunk_i < data_chunk_count; str_chunk_i++) { + strncpy((char*)data_chunk, str + data_chunk_size * str_chunk_i, data_chunk_size + 1); + if (str_chunk_i == data_chunk_count - 1) { + /* Since the whole chunk gets converted into our QR code, let's wipe its tail */ + // TODO + } + QRcode *qr = QRcode_encodeData(data_chunk_size, data_chunk, + options.version, + get_qr_ec_level(options.ec_level)); + // get_qr_encode_mode(options.encode_mode), + // true); + + int line_num_to_clear = qr->width + options.border * 2; + if (!options.large) { + // Small (default) and compact (-c) modes both use 2 blocks per line + line_num_to_clear /= 2; + // Account for trailing half-block line + line_num_to_clear += 1; + } + const int clear_str_len = strlen(CLR) * line_num_to_clear + 1; + char clear_str[clear_str_len + 1]; + clear_str[0] = clear_str[clear_str_len] = '\0'; + for (int j = 0, jlen = line_num_to_clear; j < jlen; j++) { + strcat(clear_str, CLR); + } + + /* Bail out if unable to successfully execute QRcode_encodeString() */ + if (qr == NULL) { + print_error("failed to generate QR code"); + ret = 1; + goto exit; + } + + /* Convert QR code data into text */ + char *qr_code_text = qr_data_to_text(qr, + options.border, + options.invert, + !options.plain, + options.large, + options.compact); + + /* Output QR code as text */ + if (qr_code_text) { + printf("%s", qr_code_text); + } else { + print_error("failed to convert QR code data into text"); + ret = 1; + } + + QRcode_free(qr); + + /* Clean up */ + free(qr_code_text); + + // Delay between frames (in mc) + if (is_term_output) { + // Hang it here if it's just one frame + while(data_chunk_count == 1); + + // Small delay before wiping the current and showing next frame + msleep(100); + + // Wipe previously printed QR code + printf("%s", clear_str); + } + } - /* Output QR code as text */ - if (qr_code_text) { - printf("%s", qr_code_text); + // Only one iteration if outputting into a file + if (!is_term_output) { + break; + } + } } else { - print_error("failed to convert QR code data into text"); - ret = 1; - } + QRcode *qr = QRcode_encodeString(str, + options.version, + get_qr_ec_level(options.ec_level), + get_qr_encode_mode(options.encode_mode), + true); + + /* Bail out if unable to successfully execute QRcode_encodeString() */ + if (qr == NULL) { + print_error("failed to generate QR code"); + ret = 1; + goto exit; + } + + /* Convert QR code data into text */ + char *qr_code_text = qr_data_to_text(qr, + options.border, + options.invert, + !options.plain, + options.large, + options.compact); + + /* Output QR code as text */ + if (qr_code_text) { + printf("%s", qr_code_text); + } else { + print_error("failed to convert QR code data into text"); + ret = 1; + } - /* Clean up */ - if (qr != NULL) { QRcode_free(qr); + + /* Clean up */ + free(qr_code_text); } - free(qr_code_text); exit: return ret; diff --git a/tests.at b/tests.at index 34f5767..8fb9a7e 100644 --- a/tests.at +++ b/tests.at @@ -73,18 +73,20 @@ AT_SETUP([fails to generate an empty QR Code]) AT_CHECK_UNQUOTED([./../../qr ""], [1], [], [\ Error: no input specified -Usage: qr [[OPTIONS]] STRING +Usage: qr [[OPTIONS]] [[STRING]] or: cat FILE | qr [[OPTIONS]] Options: + -a produce animated QR code -m QR mode [[na8k]] (n = number, a = alphabet, 8 = 8-bit, k = Kanji) -v QR version [[1-40]] -e QR EC level [[lmqh]] or [[1-4]] - -l use two characters per block + -l large mode -c compact mode -b border width [[1-4]] (the default is 1) -i invert colors -p force colorless output + -u ensure output has UTF-8 BOM -h print help info and exit -V print version info and exit @@ -96,18 +98,20 @@ AT_SETUP([fails and prints help information when no arguments provided]) AT_CHECK_UNQUOTED([./../../qr], [1], [], [\ Error: no input specified -Usage: qr [[OPTIONS]] STRING +Usage: qr [[OPTIONS]] [[STRING]] or: cat FILE | qr [[OPTIONS]] Options: + -a produce animated QR code -m QR mode [[na8k]] (n = number, a = alphabet, 8 = 8-bit, k = Kanji) -v QR version [[1-40]] -e QR EC level [[lmqh]] or [[1-4]] - -l use two characters per block + -l large mode -c compact mode -b border width [[1-4]] (the default is 1) -i invert colors -p force colorless output + -u ensure output has UTF-8 BOM -h print help info and exit -V print version info and exit @@ -117,18 +121,20 @@ AT_CLEANUP ## 12 AT_SETUP([prints help information when help flag is set]) AT_CHECK_UNQUOTED([./../../qr -h], [0], [\ -Usage: qr [[OPTIONS]] STRING +Usage: qr [[OPTIONS]] [[STRING]] or: cat FILE | qr [[OPTIONS]] Options: + -a produce animated QR code -m QR mode [[na8k]] (n = number, a = alphabet, 8 = 8-bit, k = Kanji) -v QR version [[1-40]] -e QR EC level [[lmqh]] or [[1-4]] - -l use two characters per block + -l large mode -c compact mode -b border width [[1-4]] (the default is 1) -i invert colors -p force colorless output + -u ensure output has UTF-8 BOM -h print help info and exit -V print version info and exit @@ -137,7 +143,7 @@ AT_CLEANUP ## 13 AT_SETUP([prints version informaton when version flag is set]) -AT_CHECK_UNQUOTED([./../../qr -V], [0], [qr 1.0.0 +AT_CHECK_UNQUOTED([./../../qr -V], [0], [qr 2.0.0 ], []) AT_CLEANUP From c6bb612e86409f89bfe4f5f161eb0da8ee9b5bed Mon Sep 17 00:00:00 2001 From: Sunshine Date: Mon, 18 Oct 2021 20:49:12 -1000 Subject: [PATCH 2/3] improve Makefile and config.mk --- Makefile | 2 +- config.mk | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 771aef3..8fb5786 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ uninstall: test: $(PROG) autom4te --no-cache -f -l autotest -o tests tests.at ./tests \ - FONT=$(FONT) \ + FONT="FreeMono" \ INPUT='Ünic0d3wörd 参 я' \ EXTRA_LONG_INPUT="参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し" .PHONY: test diff --git a/config.mk b/config.mk index a74abc3..97667aa 100644 --- a/config.mk +++ b/config.mk @@ -1,18 +1,17 @@ -# qr version -VERSION = 2.0.0 - # program name PROG = qr -# font used in tests -FONT = FreeMono +# program version +VERSION = 2.0.0 +# # Customize below to fit your system +# # paths PREFIX = /usr/local -# libs +# libraries LIBS = -lm -lqrencode # flags From 3aa198924f75ded03494f986f4bd585e2ef0cd3c Mon Sep 17 00:00:00 2001 From: Sunshine Date: Mon, 18 Oct 2021 20:59:35 -1000 Subject: [PATCH 3/3] fix CI tests --- .github/workflows/ci.yml | 43 +++++++++++++++++++++++++++++++--------- Makefile | 16 +++++++-------- tests.at | 26 ++++++++++++------------ 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7c40df..d337b64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,15 +11,26 @@ jobs: strategy: matrix: - include: - - os: ubuntu-18.04 - - os: ubuntu-20.04 - - os: macos-10.15 - - os: macos-11 + os: + - ubuntu-18.04 + - ubuntu-20.04 + - macos-10.15 + - macos-11 + cc: + - gcc + - clang + arch: + - amd64 + - arm64 + - arm + - ppc64le + - s390x continue-on-error: true steps: + - run: git config --global core.autocrlf false + - uses: actions/checkout@v2 - name: Resolve dependencies (Ubuntu) @@ -30,7 +41,7 @@ jobs: imagemagick \ libqrencode-dev \ zbar-tools - if: matrix.os == 'ubuntu-18.04' || matrix.os == 'ubuntu-20.04' + if: contains(matrix.os, 'ubuntu') - name: Resolve dependencies (macOS) run: | @@ -41,12 +52,19 @@ jobs: brew tap homebrew/cask-fonts brew install --cask font-freefont convert -font FreeMono label:"Unable to revert mtime: /Library/Fonts fix" png:- > /dev/null - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' + if: contains(matrix.os, 'macos') - name: Build run: make - - name: Test + - name: Test (Ubuntu) + shell: 'script --return --quiet --command "bash {0}"' + if: contains(matrix.os, 'ubuntu') + run: make test + + - name: Test (macOS) + shell: bash -l {0} + if: contains(matrix.os, 'macos') run: make test - name: Print test logs @@ -56,7 +74,14 @@ jobs: - name: Install run: PREFIX=/usr/local sudo make install - - name: Run + - name: Run (Ubuntu) + shell: 'script --return --quiet --command "bash {0}"' + if: contains(matrix.os, 'ubuntu') + run: /usr/local/bin/qr Success + + - name: Run (macOS) + shell: bash -l {0} + if: contains(matrix.os, 'macos') run: /usr/local/bin/qr Success - name: Uninstall diff --git a/Makefile b/Makefile index 8fb5786..b747d54 100644 --- a/Makefile +++ b/Makefile @@ -15,20 +15,20 @@ clean: .PHONY: clean install: all - echo installing executable file to $(DESTDIR)$(PREFIX)/bin - install -d $(DESTDIR)$(PREFIX)/bin - install -m 755 $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG) + @echo installing executable file into $(DESTDIR)$(PREFIX)/bin + @install -d $(DESTDIR)$(PREFIX)/bin + @install -m 755 $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG) .PHONY: install uninstall: - echo removing executable file from $(DESTDIR)$(PREFIX)/bin - rm -f $(DESTDIR)$(PREFIX)/bin/$(PROG) + @echo removing executable file from $(DESTDIR)$(PREFIX)/bin + @rm -f $(DESTDIR)$(PREFIX)/bin/$(PROG) .PHONY: uninstall test: $(PROG) - autom4te --no-cache -f -l autotest -o tests tests.at - ./tests \ + @autom4te --no-cache -f -l autotest -o tests tests.at + @./tests \ FONT="FreeMono" \ - INPUT='Ünic0d3wörd 参 я' \ + INPUT="Ünic0d3wörd 参 я" \ EXTRA_LONG_INPUT="参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し参考文献に掲載されている文章等を抜粋し" .PHONY: test diff --git a/tests.at b/tests.at index 8fb9a7e..2a83065 100644 --- a/tests.at +++ b/tests.at @@ -3,7 +3,7 @@ m4_define([AT_PACKAGE_STRING], [qr]) AT_INIT AT_COLOR_TESTS -AT_BANNER([QR-Code tests]) +AT_BANNER([Integration tests for qr]) ## 1 AT_SETUP([generates proper QR Code]) @@ -15,62 +15,62 @@ AT_CLEANUP ## 2 AT_SETUP([generates proper QR Code using inverted colors]) AT_CHECK_UNQUOTED([ - convert -background white -fill black -font "${FONT}" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -i "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background white -fill black -font "$FONT" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -i "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 3 AT_SETUP([generates proper QR Code using compact blocks]) AT_CHECK_UNQUOTED([ - convert -background black -fill white -font "${FONT}" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -c "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background black -fill white -font "$FONT" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -c "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 4 AT_SETUP([generates proper QR Code using compact blocks and inverted colors]) AT_CHECK_UNQUOTED([ - convert -background white -fill black -font "${FONT}" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -ci "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background white -fill black -font "$FONT" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -ci "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 5 AT_SETUP([generates proper QR Code using large blocks]) AT_CHECK_UNQUOTED([ - convert -background black -fill white -font "${FONT}" -pointsize 4 -interline-spacing -1 label:"$(./../../qr -l "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background black -fill white -font "$FONT" -pointsize 4 -interline-spacing -1 label:"$(./../../qr -l "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 6 AT_SETUP([generates proper QR Code using large blocks and inverted colors]) AT_CHECK_UNQUOTED([ - convert -background white -fill black -font "${FONT}" -pointsize 4 -interline-spacing -1 label:"$(./../../qr -li "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background white -fill black -font "$FONT" -pointsize 4 -interline-spacing -1 label:"$(./../../qr -li "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 7 AT_SETUP([generates proper QR Code using large compact blocks]) AT_CHECK_UNQUOTED([ - convert -background black -fill white -font "${FONT}" -pointsize 4 -interline-spacing -1 label:"$(./../../qr -lc "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background black -fill white -font "$FONT" -pointsize 4 -interline-spacing -1 label:"$(./../../qr -lc "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 8 AT_SETUP([generates proper QR Code using large compact blocks and inverted colors]) AT_CHECK_UNQUOTED([ - convert -background white -fill black -font "${FONT}" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -lci "${INPUT}")" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background white -fill black -font "$FONT" -pointsize 9 -interline-spacing -1 label:"$(./../../qr -lci "$INPUT")" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 9 AT_SETUP([generates proper QR Code with default settings using stdin]) AT_CHECK_UNQUOTED([ - convert -background black -fill white -font "${FONT}" -pointsize 9 -interline-spacing -1 label:"$(echo "${INPUT}" | ./../../qr)" png:- | zbarimg -q png:- | grep -q "QR-Code:${INPUT}" || exit 1 + convert -background black -fill white -font "$FONT" -pointsize 9 -interline-spacing -1 label:"$(echo "$INPUT" | ./../../qr)" png:- | zbarimg -q png:- | grep -q "QR-Code:$INPUT" || exit 1 ], [0], [], []) AT_CLEANUP ## 10 AT_SETUP([fails to generate an empty QR Code]) -AT_CHECK_UNQUOTED([./../../qr ""], [1], [], [\ +AT_CHECK_UNQUOTED([../../qr ""], [1], [], [\ Error: no input specified Usage: qr [[OPTIONS]] [[STRING]] @@ -120,7 +120,7 @@ AT_CLEANUP ## 12 AT_SETUP([prints help information when help flag is set]) -AT_CHECK_UNQUOTED([./../../qr -h], [0], [\ +AT_CHECK_UNQUOTED([../../qr -h], [0], [\ Usage: qr [[OPTIONS]] [[STRING]] or: cat FILE | qr [[OPTIONS]] @@ -143,13 +143,13 @@ AT_CLEANUP ## 13 AT_SETUP([prints version informaton when version flag is set]) -AT_CHECK_UNQUOTED([./../../qr -V], [0], [qr 2.0.0 +AT_CHECK_UNQUOTED([../../qr -V], [0], [qr 2.0.0 ], []) AT_CLEANUP ## 14 AT_SETUP([fails if the input is too long]) -AT_CHECK_UNQUOTED([./../../qr "${EXTRA_LONG_INPUT}"], [1], [], [\ +AT_CHECK_UNQUOTED([../../qr "${EXTRA_LONG_INPUT}"], [1], [], [\ Error: failed to generate QR code ]) AT_CLEANUP