logo

utils-std

Collection of commonly available Unix tools
commit: b27b9ab570f546ba313ec35f5c22af23d68af000
parent 3054e78a15f98c06726c352c945813e2127a19e0
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Fri, 26 Jul 2024 15:24:48 +0200

cmd/env: switch to getopt_long proper

Diffstat:

Mcmd/env.13+--
Mcmd/env.c43++++++++++++++++++++-----------------------
Mtest-cmd/env.sh13++++++++++---
3 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/cmd/env.1 b/cmd/env.1 @@ -11,7 +11,6 @@ .Nm .Op Fl i .Op Fl u Ar name -.Op Fl -unset= Ns Ar name .Op Ar name Ns = Ns Ar value .Op Ar command Op Ar argument... .Sh DESCRIPTION @@ -23,7 +22,7 @@ The environment can be modified via the following options: .Bl -tag -width Ds .It Fl i Ignore the existing environment. -.It Fl u Ar name | Fl -unset= Ns Ar name +.It Fl u Ar name Removes the variable named .Ar name from the new environment. diff --git a/cmd/env.c b/cmd/env.c @@ -10,6 +10,9 @@ #include <stdlib.h> // putenv #include <string.h> // strchr, strerror #include <unistd.h> // getopt, opt* +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif extern char **environ; char *envclear[1]; @@ -34,17 +37,30 @@ do_export() static void usage() { - fprintf(stderr, "env [-i] [-u key | --unset=key] [key=value ...] [command [args]]\n"); + fprintf(stderr, "env [-i] [-u key] [key=value ...] [command [args]]\n"); } int main(int argc, char *argv[]) { - int c; bool flag_i = false; - char *val; - while((c = getopt(argc, argv, ":iu:-:")) != -1) + int c = -1; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"ignore-environment", no_argument, 0, 'i'}, + {"unset", required_argument, 0, 'u'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + while((c = getopt_long(argc, argv, "+:iu:", opts, NULL)) != -1) +#else + while((c = getopt(argc, argv, ":iu:")) != -1) +#endif { switch(c) { @@ -54,25 +70,6 @@ main(int argc, char *argv[]) case 'u': unsetenv(optarg); break; - case '-': - val = strchr(optarg, '='); - if(val == NULL) - { - fprintf(stderr, "env: Error: Missing = in long option\n"); - return 1; - } - - *val = 0; - val++; - - if(strcmp(optarg, "unset") != 0) - { - fprintf(stderr, "env: Error: Unknown long option --%s\n", optarg); - return 1; - } - unsetenv(val); - - break; case ':': fprintf(stderr, "env: Error: Missing operand for option: '-%c'\n", optopt); usage(); diff --git a/test-cmd/env.sh b/test-cmd/env.sh @@ -11,8 +11,9 @@ then exit 0 fi -target="$(dirname "$0")/../cmd/env" -plans=8 +WD="$(dirname "$0")/../" +target="${WD}/cmd/env" +plans=9 . "$(dirname "$0")/tap.sh" t reset '-i FOO=BAR' 'FOO=BAR @@ -21,7 +22,13 @@ t reset_chain "-i FOO=BAR $target" 'FOO=BAR ' t uflag "-i FOOZ=BARZ $target -u FOOZ FOO=BAR" 'FOO=BAR ' -t unsetflag "-i FOOZ=BARZ $target --unset=FOOZ FOO=BAR" 'FOO=BAR +if grep -q HAS_GETOPT_LONG "${WD}/config.mk"; then + t unsetflag "-i FOOZ=BARZ $target --unset=FOOZ FOO=BAR" 'FOO=BAR +' +else + skip unsetflag 'Lacks getopt_long' +fi +t posix_me_harder "-i FOO=BAR sh -c echo" ' ' t exec_true 'true' '' t exec_echo 'echo' '