From 2c7f3f30e4ffdaa97aa62697536e678ea75b3c38 Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 3 Dec 2023 19:47:40 -0700 Subject: [PATCH] documentation --- intcmp/Makefile | 1 + intcmp/intcmp.1 | 63 +++++++++++++++++++++++++++++++++++++++++ intcmp/intcmp.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 intcmp/Makefile create mode 100644 intcmp/intcmp.1 create mode 100644 intcmp/intcmp.c diff --git a/intcmp/Makefile b/intcmp/Makefile new file mode 100644 index 0000000..7f43062 --- /dev/null +++ b/intcmp/Makefile @@ -0,0 +1 @@ +intcmp: intcmp.c diff --git a/intcmp/intcmp.1 b/intcmp/intcmp.1 new file mode 100644 index 0000000..614de1a --- /dev/null +++ b/intcmp/intcmp.1 @@ -0,0 +1,63 @@ +.TH intcmp 1 + +.SH NAME + +intcmp \(en compare integers + +.SH SYNOPSIS + +intcmp +.RB ( -h ) +.RB ( -e ( -g )|( -l ))|( -g ( -e )|( -l ))|( -l ( -e )|( -g )) +.RB [ integer ] +.RB [ integer... ] + +.SH DESCRIPTION + +Intcmp compares integers. + +.SH USAGE + +The -e option permits given integers to be equal to each other. If combined +with -g or -l, only adjacent integers in the argument sequence can be equal. +.PP +The -g option permits a given integer to be greater than the following integer. +.PP +The -l option permits a given integer to be less than the following integer. +.PP +It may help to think of the -e, -g, and -l options as equivalent to the +infix algebraic "=", ">", and "<" operators respectively, with each option +putting its symbol between every given integer. For example, +.R intcmp -l 1 2 3 +is equivalent to evaluating "1 < 2 < 3". + +.SH DIAGNOSTICS + +Intcmp exits 0 for a valid expression and 1 for an invalid expression. +.PP +Intcmp prints a debug message and exits with the appropriate sysexits(3) error +code in the event of an error. + +.SH BUGS + +There are multiple ways to express compound comparisons; "less than or equal +to" can be -le or -el, for example. +.PP +The inequality comparison is -gl or -lg for "less than or greater than"; this +is elegant but unintuitive. +.PP +-egl, "equal to or less than or greater than", exits 0 no matter what for valid +program usage and may be abused to function as an integer validator. +Use str(1) instead. + +.SH STANDARDS + +This utility recreates functionality that in POSIX is fulfilled by test(1). + +.SH COPYRIGHT + +Public domain. + +.SH SEE ALSO + +str(1), test(1) diff --git a/intcmp/intcmp.c b/intcmp/intcmp.c new file mode 100644 index 0000000..09d37e7 --- /dev/null +++ b/intcmp/intcmp.c @@ -0,0 +1,75 @@ +#include /* errno */ +#include /* fprintf(3), stderr */ +#include /* strtol(3), size_t */ +#ifndef EX_USAGE +# include /* EX_USAGE */ +#endif +#include /* getopt(3), optind */ + +/* 0b00? */ /* Equal | -e | 0b001 | 1 */ +#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ +/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ +#define GREATER 0x02 /* Less | -l | 0b100 | 4 */ +/* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */ +#define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */ + +static char *program_name = "intcmp"; + +int main(int argc, char *argv[]){ + int c; + size_t i; + unsigned char mode; + int r; /* reference integer */ + + mode = 0; + + if(argc < 3) + goto usage; + + while((c = getopt(argc, argv, "egl")) != -1) + switch(c){ + case 'e': mode |= EQUAL; break; + case 'g': mode |= GREATER; break; + case 'l': mode |= LESS; break; + default: goto usage; + } + + if(optind + 2 /* ref cmp */ > argc){ +usage: fprintf(stderr, + "Usage: %s (-h)\n" + "\t" "(-e (-g)|(-l))\n" + "\t" "|(-g (-e)|(-l))\n" + "\t" "|(-l (-e)|(-g))\n" + "\t\t" "[integer] [integer...]\n", + argv[0] == NULL ? program_name : argv[0]); + return EX_USAGE; + } + + i = optind; + + do{ c = strtol(argv[i], &argv[i], 10); + if(*argv[i] != '\0' || errno != 0){ + fprintf(stderr, "%s: argument #%d: Invalid integer\n", + argv[0], (int)i); + return EX_USAGE; + } + + if(i == optind){ + r = c; + continue; + } + + /* rule enforcement; if a mode isn't permitted and the numbers + * correspond to it, return 1 */ + if( (!(mode & EQUAL) && r == c) + || (!(mode & GREATER) && r > c) + || (!(mode & LESS) && r < c)) + return 1; + else if((mode ^ EQUAL) != 0) /* if the mode isn't == + * make sure the numbers are in order by comparing the + * newest number to the last */ + r = c; + }while(++i < argc); + + return 0; +}