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

Alejandro Colomar (man-pages)
2021-08-09T06:40:53Z

Hi Michael,

On 8/9/21 12:11 AM, Michael Kerrisk (man-pages) wrote:
>
> 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 :-).

Yes, I should :-)

>
> 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);
> }
>

Nice!

Thanks,

Alex

--
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/