diff options
| author | Mattias Andrée <m@maandree.se> | 2025-12-27 22:37:47 +0100 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2025-12-27 22:37:47 +0100 |
| commit | 4506c1e56ec89ad42c1a37f4b9b41204e4d991d1 (patch) | |
| tree | 477d80ea90a4d827e70bb5d85781c1e366cee124 | |
| download | gluhncheck-4506c1e56ec89ad42c1a37f4b9b41204e4d991d1.tar.gz gluhncheck-4506c1e56ec89ad42c1a37f4b9b41204e4d991d1.tar.bz2 gluhncheck-4506c1e56ec89ad42c1a37f4b9b41204e4d991d1.tar.xz | |
First commit
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
| -rw-r--r-- | .gitignore | 15 | ||||
| -rw-r--r-- | LICENSE | 15 | ||||
| -rw-r--r-- | Makefile | 37 | ||||
| -rw-r--r-- | README | 40 | ||||
| -rw-r--r-- | config.mk | 8 | ||||
| -rw-r--r-- | luhncheck.1 | 85 | ||||
| -rw-r--r-- | luhncheck.c | 81 |
7 files changed, 281 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..968c03a --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*\#* +*~ +*.o +*.a +*.lo +*.su +*.so +*.so.* +*.dll +*.dylib +*.gch +*.gcov +*.gcno +*.gcda +/luhncheck @@ -0,0 +1,15 @@ +ISC License + +© 2025 Mattias Andrée <m@maandree.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2cf17d4 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OBJ =\ + luhncheck.o + +HDR = + +all: luhncheck +$(OBJ): $(HDR) + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +luhncheck: $(OBJ) + $(CC) -o $@ $(OBJ) $(LDFLAGS) + +install: luhncheck + mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1/" + cp -- luhncheck "$(DESTDIR)$(PREFIX)/bin/" + cp -- luhncheck.1 "$(DESTDIR)$(MANPREFIX)/man1/" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/luhncheck" + -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/luhncheck.1" + +clean: + -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.gch *.gcov *.gcno *.gcda + -rm -f -- luhncheck + +.SUFFIXES: +.SUFFIXES: .o .c + +.PHONY: all install uninstall clean @@ -0,0 +1,40 @@ +NAME + luhncheck - Check number with Luhn's algorithm + +SYNOPSIS + luhncheck number ... + +DESCRIPTION + The luhncheck utility checks that a number, containing a + check digit, is valid according to Luhn's algorithm. + +OPTIONS + The luhncheck utility conforms to the Base Definitions volume + of POSIX.1-2017, Section 12.2, Utility Syntax Guidelines. + + No options are supported. + +OPERANDS + The following operand is supported: + + number + Number to check. + +STDOUT + The luhncheck utility will print one line per number, in the + order they are provided in the command line, to the standard + output. Each line will be use the format + + "%s is %s\n", number, <"OK" if valid, "invalid" otherwise>. + +EXIT STATUS + The following exit values are returned: + + 0 All numbers are valid. + + 1 At least one number is invalid. + + 2 An error occured. + +SEE ALSO + gluhncheck(1) diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..f4adf12 --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = c99 + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +CFLAGS = +LDFLAGS = diff --git a/luhncheck.1 b/luhncheck.1 new file mode 100644 index 0000000..11da1e5 --- /dev/null +++ b/luhncheck.1 @@ -0,0 +1,85 @@ +.TH LUHNCHECK 1 LUHNCHECK + +.SH NAME +luhncheck \- Check number with Luhn's algorithm + +.SH SYNOPSIS +.B luhncheck +.IR number " ..." + +.SH DESCRIPTION +The +.B luhncheck +utility checks that a number, containing a check digit, +is valid according to Luhn's algorithm. + +.SH OPTIONS +The +.B luhncheck +utility conforms to the Base Definitions volume of POSIX.1-2017, +.IR "Section 12.2" , +.IR "Utility Syntax Guidelines" . +.PP +No options are supported. + +.SH OPERANDS +The following operand is supported: +.TP +.I number +Number to check. + +.SH STDIN +Not used. + +.SH INPUT FILES +None. + +.SH ENVIRONMENT VARIABLES +No environment variables affect the execution of +.BR luhncheck . + +.SH ASYNCHRONOUS EVENTS +Default. + +.SH STDOUT +The +.B luhncheck +utility will print one line per +.IR number , +in the order they are provided in the command line, +to the standard output. +Each line will be use the format + +.RS +.B \(dq%s is %s\en\(dq, +.IB number , +.RI < \fB\(dqOK\(dq\fP\ if\ valid,\ \fB\(dqinvalid\(dq\fP\ otherwise >. +.RE + +.SH STDERR +The standard error is only used for diagnostic messages. + +.SH OUTPUT FILES +None. + +.SH EXTENDED DESCRIPTION +None. + +.SH EXIT STATUS +The following exit values are returned: +.TP +0 +All +.IR number s +are valid. +.TP +1 +At least one +.I number +is invalid. +.TP +2 +An error occured. + +.SH SEE ALSO +.BR gluhncheck (1) 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; +} |
