aboutsummaryrefslogtreecommitdiffstats
path: root/luhncheck.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-12-27 22:37:47 +0100
committerMattias Andrée <m@maandree.se>2025-12-27 22:37:47 +0100
commit4506c1e56ec89ad42c1a37f4b9b41204e4d991d1 (patch)
tree477d80ea90a4d827e70bb5d85781c1e366cee124 /luhncheck.c
downloadluhncheck-4506c1e56ec89ad42c1a37f4b9b41204e4d991d1.tar.gz
luhncheck-4506c1e56ec89ad42c1a37f4b9b41204e4d991d1.tar.bz2
luhncheck-4506c1e56ec89ad42c1a37f4b9b41204e4d991d1.tar.xz
First commit
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--luhncheck.c81
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;
+}