getopt.3: Further clarification of optstring
commit87ce949275b6d4ebafc62684e4c4e5f073c9456d
authorJames O. D. Hunt <jamesodhunt@gmail.com>
Sun, 8 Aug 2021 08:41:20 +0000 (8 10:41 +0200)
committerMichael Kerrisk <mtk.manpages@gmail.com>
Mon, 9 Aug 2021 00:32:37 +0000 (9 02:32 +0200)
treeac3a42c253f834545c843bd3872987eef32032a8
parent71a62d6c3c56b2cec56858f19b8b419c1355db17
getopt.3: Further clarification of optstring

Explain that `optstring` cannot contain a semi-colon (`;`)
character.
[mtk: verified 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);
}
man3/getopt.3