getopt_long(), getopt_long_only()

Updated: April 19, 2023

Get long and short options from a command-line argument list

Synopsis:

#include <getopt.h>

int getopt_long( int argc,
                 char * const *argv,
                 const char *optstring,
                 const struct option *longopts,
                 int *longindex);

int getopt_long_only( int argc,
                      char * const *argv,
                      const char *optstring,
                      const struct option *longopts,
                      int *longindex);

extern char *optarg;
extern int optind, opterr, optopt, optreset;

Arguments:

argc
The number of entries in the argument array.
argv
The argument array that you want to parse.
optstring
A string of short options; see below.
longopts
An array of type struct option that describes the long options; see below. End the array by including an element with its name field set to NULL.
longindex
NULL, or a pointer to a location where the function can store the index of the long option in the longopts array.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The getopt_long() function is similar to getopt(), but it accepts short and long options. Long options can—but don't have to—correspond to short ones (e.g., to serve as memory aids for new users).

Note: The getopt() function is POSIX, and getopt_long() is NetBSD. They handle the short options in slightly different ways: with getopt(), optstring supports neither the leading plus sign or hyphen, nor the double colon for denoting optional arguments to options. The W; notation is also unique to getopt_long().

The optstring specifies the short options and consists of the following:

Long options start with a double hyphen (--) and can be followed by an equals sign and an argument. For example:

myprogram --myoption=somevalue

The user can abbreviate long option names; if getopt_long() can't determine the option, it returns a question mark.

Use the option structure to define the long options:

struct option {
    const char *name;
    int has_arg;
    int *flag;
    int val;
};

The members include:

name
The option name without any leading hyphens.
has_arg
Whether the option has an argument; one of:
  • no_argument — no argument to the option is expected
  • required_argument — an argument to the option is required, but the equals sign is optional. If the user doesn't specify the equals sign, getopt_long interprets the next array element as the argument.
  • optional_argument — an argument to the option may be provided; optarg is non-NULL if the user specified an argument. The user needs to specify the equals sign, or else getopt_long doesn't associate the argument with the option.
flag, val
How to report or act on the long option:
  • If flag isn't NULL, then getopt_long() sets *flag to the value in the val field and then returns 0.
  • If flag is NULL, then getopt_long() returns the value that you specified in val. Setting flag to NULL and setting val to the corresponding short option makes this function act like getopt().

If the longindex argument isn't NULL, then getopt_long() sets *longindex to the index of the long option in the longopts array.

If you want to use getopt_long() to evaluate multiple sets of arguments or to evaluate a single set of arguments multiple times, set optreset and optind to 1 before starting each additional set of calls to getopt_long().

The getopt_long_only() function behaves identically to getopt_long(), except that long options may start with a single or double hyphen (- or --). If an option starting with a single hyphen doesn't match a long option but does match a single-character option, the single-character option is returned. If getopt_long_only() can't determine the option, it returns a question mark.

Returns:

One of the following:

Environment variables:

POSIXLY_CORRECT
If set, option processing stops when the first non-option is found, and a leading - or + in optstring is ignored.

Examples:

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int decompress_it = 0;
int loop = 0;

void usage()
{
  printf ("Usage: my_program [-ab] [-f path] [-m [message]] [--buffered]\n");
  printf ("                  [--decompress] [--file path] [--loop [num_iterations]]\n");
}

int main (int argc, char **argv)
{
    int fd = -1;
    int longindex;
    int i, ch;
    int num_loops;

    static struct option longopts[] = {
        { "buffered", no_argument,  NULL, 'b' },
        { "file",   required_argument, NULL, 'f' },
        { "decompress",  no_argument,  &decompress_it, 1 },
        { "loop",  optional_argument,  &loop, 1 },
        { NULL, 0, NULL, 0 }
    };

    /* Uncomment this to suppress getopt_long()'s messages about missing arguments: */
    // opterr = 0;

    while ((ch = getopt_long(argc, argv, "abf:m::", longopts, &longindex)) != -1) {
            
        switch (ch) {
        case '\1':
                /* Non-options are sent here if optstring starts with a hyphen. */
                printf ("  Option \\1: %s\n", optarg == NULL ? "NULL" : optarg);
                break;
        case 'a':
                printf ("   -a\n");
                break;
        case 'b':
                printf ("   -b or --buffered\n");
                break;
        case 'f':
	        printf ("   -f %s or --file=%s\n", optarg, optarg);
                if ((fd = open(optarg, O_RDONLY, 0)) == -1)
                   printf("      Unable to open the file '%s'\n", optarg);
                break;
        case 'm':
                if (optarg == NULL) {
                   printf ("   -m with no argument\n");
                } else {
                   printf ("   -m %s\n", optarg);
                }
                break;
        case 0:
                /* Process any long options that set a variable. */

                if (decompress_it) {
                    printf ("   --decompress.\n");
                }
                if (loop) {
                     if (optarg == NULL) {
                         printf ("   --loop with no argument; using the default of 10 loops.\n");
                         num_loops = 10;
                     } else {
                         num_loops = atoi (optarg);
                         printf ("   --loop=%d\n", num_loops);
                     }
                }
                break;
        case ':':
                /* An argument is missing and optstring starts with a colon;
                   handle this appropriately. */
                break;
        case '?':
                /* Ambiguous or unknown option, or an argument is missing and optstring
                   doesn't start with a colon; handle this appropriately. */
                break;
        default:
                usage();
                return EXIT_FAILURE;
        }
    }
    
    printf ("Done processing the options; argc = %d; optind=%d\n", argc, optind);

    for (i = optind; i < argc; i++) {
       printf ("    %s\n", argv[i]);
    }

    return EXIT_SUCCESS;
}

Classification:

NetBSD

Safety:  
Cancellation point Yes
Interrupt handler No
Signal handler No
Thread No