Re: [PATCH 10/23] getopt.3: Further clarification of optstring

Michael Kerrisk (man-pages)
2021-08-08T22:11:45Z

Hello James and Alex,

On 8/8/21 10:41 AM, Alejandro Colomar wrote:
> From: "James O. D. Hunt" <jamesodhunt@gmail.com>
>
> Explain that `optstring` cannot contain a semi-colon (`;`) character.
>
> Also explain that `optstring` can include `+` as an option character,
> possibly in addition to that character being used as the first character
> in `optstring` to denote `POSIXLY_CORRECT` behaviour.
>
> Signed-off-by: James O. D. Hunt <jamesodhunt@gmail.com>
> Signed-off-by: Alejandro Colomar <alx.manpages@gmail.com>
> ---
> man3/getopt.3 | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/man3/getopt.3 b/man3/getopt.3
> index ce4c28088..315224c64 100644
> --- a/man3/getopt.3
> +++ b/man3/getopt.3
> @@ -130,7 +130,7 @@ A legitimate option character is any visible one byte
> .BR ascii (7)
> character (for which
> .BR isgraph (3)
> -would return nonzero) that is not \(aq\-\(aq or \(aq:\(aq.
> +would return nonzero) that is not \(aq\-\(aq, \(aq:\(aq or \(aq;\(aq.
> If such a
> character is followed by a colon, the option requires an argument, so
> .BR getopt ()
> @@ -166,6 +166,14 @@ If the first character of
> .B POSIXLY_CORRECT
> is set, then option processing stops as soon as a nonoption argument is
> encountered.
> +If \(aq+\(aq is not the first character of
> +.IR optstring ,
> +it is treated as a normal option.
> +If
> +.B POSIXLY_CORRECT
> +behaviour is required in this case
> +.I optstring
> +will contain two \(aq+\(aq symbols.
> If the first character of \fIoptstring\fP is \(aq\-\(aq, then
> each nonoption \fIargv\fP-element is handled as if it were the argument of
> an option with character code 1. (This is used by programs that were

Thanks. The patch is good and I applied it

@James: it would be helpful to explain in the commit
message how you verified these details.

@Alex: do not be shy of asking people to improve there commit
messages in this way :-).

See my modified commit message below.

Cheers,

Michael

getopt.3: Further clarification of optstring

Explain that `optstring` cannot contain a semi-colon (`;`)
character.
[mtk: verfiried with a small test program; see also posix/getopt.c
in the glibc sources:

if (temp == NULL || c == ':' || c == ';')
{
if (print_errors)
fprintf (stderr, _("%s: invalid option -- '%c'\n"), argv[0], c);
d->optopt = c;
return '?';
}
]

Also explain that `optstring` can include `+` as an option
character, possibly in addition to that character being used as
the first character in `optstring` to denote `POSIXLY_CORRECT`
behaviour.
[mtk: verified with a small test program.]

Test program below. Example runs:

$ ./a.out -+
opt = 43 (+); optind = 2
Got plus
$ ./a.out -';'
./a.out: invalid option -- ';'
opt = 63 (?); optind = 2; optopt = 59 (;)
Unrecognized option (-;)
Usage: ./a.out [-p arg] [-x]

Signed-off-by: James O. D. Hunt <jamesodhunt@gmail.com>
Signed-off-by: Alejandro Colomar <alx.manpages@gmail.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>

8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---
#include <ctype.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define printable(ch) (isprint((unsigned char) ch) ? ch : '#')

static void /* Print "usage" message and exit */
usageError(char *progName, char *msg, int opt)
{
if (msg != NULL && opt != 0)
fprintf(stderr, "%s (-%c)\n", msg, printable(opt));
fprintf(stderr, "Usage: %s [-p arg] [-x]\n", progName);
exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
int opt, xfnd;
char *pstr;

xfnd = 0;
pstr = NULL;

while ((opt = getopt(argc, argv, "p:x+;")) != -1) {
printf("opt =%3d (%c); optind = %d", opt, printable(opt), optind);
if (opt == '?' || opt == ':')
printf("; optopt =%3d (%c)", optopt, printable(optopt));
printf("\n");

switch (opt) {
case 'p': pstr = optarg; break;
case 'x': xfnd++; break;
case ';': printf("Got semicolon\n"); break;
case '+': printf("Got plus\n"); break;
case ':': usageError(argv[0], "Missing argument", optopt);
case '?': usageError(argv[0], "Unrecognized option", optopt);
default:
printf("Unexpected case in switch()\n");
exit(EXIT_FAILURE);
}
}

if (xfnd != 0)
printf("-x was specified (count=%d)\n", xfnd);
if (pstr != NULL)
printf("-p was specified with the value \"%s\"\n", pstr);
if (optind < argc)
printf("First nonoption argument is \"%s\" at argv[%d]\n",
argv[optind], optind);
exit(EXIT_SUCCESS);
}

--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/