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:
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' '