getopt: explicitly ask for POSIX mode on POSIXLY_CORRECT

GNU libc's getopt_long(3) have the tradition of not shuffling arguments
to find options when either POSIXLY_CORRECT is defined in environment
variables or '+' prepended in short options. Hence, the current code
base is fine as is fine as is for util-linux built with GNU libc.

However, musl libc only honour POSIX convention when short options
prepended with '+'. musl libc doesn't care about POSIXLY_CORRECT.
Thus, the behaviour of util-linux's getopt(1) that linked with musl-libc
doesn't match with its own documentation.

Let's make sure a '+' is always prepended to short options if
POSIXLY_CORRECT is defined.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
This commit is contained in:
Đoàn Trần Công Danh 2021-01-05 20:55:46 +07:00
parent 0d182490e3
commit 27fd7278a1
3 changed files with 21 additions and 4 deletions

View File

@ -205,6 +205,7 @@ usrbin_exec_PROGRAMS += getopt
dist_man_MANS += misc-utils/getopt.1
PATHFILES += misc-utils/getopt.1
getopt_SOURCES = misc-utils/getopt.c
getopt_LDADD = $(LDADD) libcommon.la
getoptexampledir = $(docdir)
dist_getoptexample_DATA = \
misc-utils/getopt-example.bash \

View File

@ -382,7 +382,11 @@ will be parsed. It will still do parameter shuffling (i.e., all
non\-option parameters are output at the end), unless the
environment variable
.B POSIXLY_CORRECT
is set.
is set, in which case,
.B getopt
will prepend a
.RB ' + '
before short options automatically.
.PP
The environment variable
.B GETOPT_COMPATIBLE

View File

@ -69,6 +69,7 @@
#include "closestream.h"
#include "nls.h"
#include "strutils.h"
#include "xalloc.h"
/* NON_OPT is the code that is returned getopt(3) when a non-option is
@ -275,6 +276,18 @@ static void add_longopt(struct getopt_control *ctl, const char *name, int has_ar
}
static void add_short_options(struct getopt_control *ctl, char *options)
{
free(ctl->optstr);
if (*options != '+' && getenv("POSIXLY_CORRECT"))
ctl->optstr = strappend("+", options);
else
ctl->optstr = xstrdup(options);
if (!ctl->optstr)
err_oom();
}
/*
* Register several long options. options is a string of long options,
* separated by commas or whitespace. This nukes options!
@ -414,8 +427,7 @@ int main(int argc, char *argv[])
getopt_long_fp = getopt_long_only;
break;
case 'o':
free(ctl.optstr);
ctl.optstr = xstrdup(optarg);
add_short_options(&ctl, optarg);
break;
case 'l':
add_long_options(&ctl, optarg);
@ -455,7 +467,7 @@ int main(int argc, char *argv[])
if (optind >= argc)
parse_error(_("missing optstring argument"));
else {
ctl.optstr = xstrdup(argv[optind]);
add_short_options(&ctl, argv[optind]);
optind++;
}
}