diff options
Diffstat (limited to 'luhncheck.c')
| -rw-r--r-- | luhncheck.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/luhncheck.c b/luhncheck.c new file mode 100644 index 0000000..51f04ab --- /dev/null +++ b/luhncheck.c @@ -0,0 +1,81 @@ +/* See LICENSE file for copyright and license details. */ +#include <libsimple-arg.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +NUSAGE(2, "number ..."); + + +static int +check_luhn(const char *s) +{ + unsigned sum = 0; + + switch (strlen(s) & 1U) { + for (;;) { + case 0: + if ('0' <= *s && *s <= '4') + sum += 2U * (unsigned)(*s - '0'); + else if ('5' <= *s && *s <= '9') + sum += 2U * (unsigned)(*s - '0') - 9U; + else if (*s) + return 0; + else + break; + s++; + + case 1: + if ('0' <= *s && *s <= '9') + sum += (unsigned)(*s - '0'); + else if (*s) + return 0; + else + break; + s++; + + sum %= 10U; + } + } + + return (sum % 10U) == 0U; +} + + +int +main(int argc, char *argv[]) +{ + int use_colour; + int ret = 0; + int r, ok; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if (!argc) + usage(); + + use_colour = isatty(STDOUT_FILENO); + + for (; *argv; argv++) { + ok = check_luhn(*argv); + ret |= !ok; + r = printf("%s%s %s%s\n", use_colour ? ok ? "\033[1;32m" : "\033[1;31m" : "", + *argv, ok ? "is OK" : "is invalid", use_colour ? "\033[m" : ""); + if (r < 0) { + fprintf(stderr, "%s: printf: %s\n", argv0, strerror(errno)); + exit(2); + } + } + + if (fflush(stdout) || fclose(stdout)) { + fprintf(stderr, "%s: printf: %s\n", argv0, strerror(errno)); + exit(2); + } + + return ret; +} |
