Next: , Up: (dir)

Arg_parser Manual

This manual is for Arg_parser (version 1.21, 10 March 2026).


Copyright © 2006-2026 Antonio Diaz Diaz.

This manual is free documentation: you have unlimited permission to copy, distribute, and modify it.


Next: , Previous: Top, Up: Top

1 Introduction

Arg_parser is an argument parser that follows POSIX and GNU conventions for command-line arguments. There exist C++ and C versions of Arg_parser. The C++ version is implemented as a C++ class, while the C version is implemented as a single struct plus associated functions. Both are simpler, easier to use, and safer than 'getopt_long'.

For maximum stability, Arg_parser is self-contained. It extracts all the information it needs from its arguments to avoid referring to them later. This avoids index-out-of-bounds errors and allows the parser object to be passed as argument to other functions for further analysis.

Arg_parser does not modify its arguments (argc, argv), nor uses any global variables.

The C++ version of Arg_parser can also parse options from configuration files.

Arg_parser was developed as the argument parser for GNU moe, because moe's argument parsing is rather complex. Then I used it in my other projects, including GNU ddrescue, GNU ed, lzip, GNU ocrad, tarlz, and zutils, with excellent results.

1.1 Differences with 'getopt' and 'getopt_long'.

'getopt' parses the options one by one, which requires internal state. Part of this state is stored in several global variables, and part of it is hidden. For example, the POSIX specification of 'getopt' states that:

When an element of argv[] contains multiple option characters, it is unspecified how getopt() determines which options have already been processed.

Parsing the options one by one is also a lot of work for the application, which must check for errors (invalid option, missing option argument, etc) for each option. 'getopt' is the 1970s way of parsing command-line arguments.

'getopt_long' is a not-very-well-designed extension on top of 'getopt'. In addition to parsing the options one by one as 'getopt' does, 'getopt_long' accepts configuration data from two overlapping sources, which makes it easy for errors in the configuration to remain undetected. For example, a certain long option can be declared to be equivalent to a given short option, but both forms of the option may contain contradictory requirements for the option's argument.

OTOH, Arg_parser parses the whole command line at once and fills a struct with the results, like 'gmtime_r' and 'stat' do. This way, errors are checked once, there is no need to permute the elements of argv, and the struct returned can be used undisturbed by later changes in argv.

Finally, using Arg_parser instead of 'getopt_long' reduces the size of your source code because, as 'getopt_long' is not available on all systems, a portable program using it needs to ship its (larger) source anyway.


Next: , Previous: Introduction, Up: Top

2 Syntax of command-line arguments

POSIX recommends these conventions for command-line arguments. Arg_parser makes it easy to implement them.

GNU adds long options to these conventions:

The syntax of options with an optional argument is -<short_option><argument> (without whitespace), or --<long_option>=<argument>.

The syntax of options with an empty argument is -<short_option> "", --<long_option> "", or --<long_option>="".


Next: , Previous: Argument syntax, Up: Top

3 Using the C++ version of Arg_parser

The C++ version of Arg_parser is provided in the files arg_parser.h and arg_parser.cc. To learn how to use Arg_parser in your C++ programs, see C++ example, and the file main.cc in the source tarball.

3.1 Parsing arguments and reporting errors

The class 'Arg_parser' has two constructors; one to parse command-line arguments from argv, and the other to parse a single token from a configuration file or other source.

-- Data Type: struct Option

This structure describes a single option for the sake of 'Arg_parser'. The argument options must be an array of these structures, one for each option. Terminate the array with an element containing a code which is zero. 'struct Option' has the following members:

-- Member: int code

This member is the code that identifies the option, normally the short-option character. Must be different from 0. A code value outside the unsigned char range means a long-only option.

-- Member: const char * long_name

This member is the long option name. It is a zero-terminated string. A null or empty long_name means a short-only option.

-- Member: enum Has_arg has_arg

This member says whether the option takes an argument. It has four valid values: 'no', 'yes', 'maybe', and 'yesme', meaning respectively 'no argument', 'non-empty argument required', 'optional argument', and 'argument required, but it may be the empty string'. 'yesme' is not recommended.

If an empty argument is passed to an option specified as 'yesme', it must be in a separate command-line argument or specified as a long option with the empty string after the '=' character. It can't be specified as the empty string after the short option.

-- Data Type: enum Flags

The argument flags is a bit mask. You can bitwise-OR the following constants and assign them to flags to modify the way in which the arguments are parsed. flags = 0 chooses the default behavior (reorder the options to put them before the non-option arguments).

-- Constant: Flags in_order

Store the arguments in the exact order the user typed them, without reordering the options to put them before the non-option arguments.

-- Constant: Flags in_order_stop

Stop option processing when finding the first non-option argument as if the argument '--' had been found before it. Store the first non-option argument and all the arguments following it as non-option arguments, even if they begin with a hyphen. This is similar to the POSIX function 'getopt', which stops option processing after finding the first non-option argument.

-- Constant: Flags in_order_skip

Parse only the heading options. Skip the first non-option argument and all the arguments following it; do not parse nor store them. The function 'argv_index' returns the index in argv of the first argument skipped (the first non-option argument), or argc if no arguments were skipped. This mode is useful for parsing the command line of programs that invoke other programs, like timeout, xargs, or valgrind.

-- Constant: Flags neg_non_opt

Parse the negative numbers, including '-inf', '-Inf', and '-INF', as non-option arguments without reordering them. Numbers start with a digit or a period and a digit. This mode is useful for parsing the command line of tools like seq which take negative numbers as arguments.

-- Function: Arg_parser ( const int argc, const char * const argv[], const Option options[], const int flags = 0 )

Constructor. Reads the arguments in argv and parses all options, option arguments, and non-option arguments contained in them. In case of error, 'error().size()' returns nonzero.

-- Function: Arg_parser ( const char * const opt, const char * const arg, const Option options[] )

Restricted constructor. Parses a single token (plus an optional second token in case an argument is needed for an option parsed). Can be used to parse options from a configuration file one at a time. Be warned that a single token may produce an undefined number of short options. In case of error, 'error().size()' returns nonzero.

-- Function: const std::string & error () const

Use this funtion to check that the arguments have been correctly parsed by the constructor. If there was an error parsing the arguments, 'error' returns an error message explaining the cause, else it returns an empty string.

-- Function: int argv_index () const

Return the index in argv of the first argument skipped (the first non-option argument) when flags was set to 'in_order_skip'. If no arguments were skipped, argc is returned instead.

3.2 Reading the options and arguments parsed

After a successful call to the constructor, which must be checked by calling 'error', the options and arguments parsed can be accessed by means of the following functions:

-- Function: int arguments () const

This function returns the number of options and non-option arguments parsed. This number is usually different from argc.

-- Function: int code ( const int i ) const

This function returns the code of the option at position i. Valid values for i range from 0 to 'arguments() - 1'. If the code returned is nonzero, 'argument(i)' is the option's argument (or is empty if the option does not have an argument). If the code returned is zero, 'argument(i)' is a non-option argument.

-- Function: const std::string & parsed_name ( const int i ) const

This function returns the full name of the option parsed (short or long) at position i. It may be useful to produce more accurate diagnostic messages. For non-option arguments it returns the empty string.

-- Function: const std::string & argument ( const int i ) const

This function returns the argument at position i. It may be the argument of an option or a non-option argument, depending on the value returned by 'code(i)'. Valid values for i range from 0 to 'arguments() - 1'. If the argument does not exist, the empty string is returned.


Next: , Previous: C++ version, Up: Top

4 Using the C version of Arg_parser

The C version of Arg_parser is provided in the files carg_parser.h and carg_parser.c. To learn how to use Arg_parser in your C programs, see C example, and the file cmain.c in the source tarball.

4.1 Parsing arguments and reporting errors

You need to declare a variable of type 'Arg_parser', pass its address to 'ap_init' to initialize it, and check that 'ap_error' returns 0.

'struct ap_Option' is identical to 'struct Option', except that 'Has_arg' becomes 'ap_Has_arg', and the names of its four values are also prefixed with 'ap_'. See struct Option, for details about the members.

'enum ap_Flags' is identical to 'enum Flags', except that its constants are also prefixed with 'ap_'. See enum Flags, for a description of the constants.

-- Function: char ap_init ( Arg_parser * const ap, const int argc, const char * const argv[], const ap_Option options[], const int flags )

Reads the arguments in argv and parses all options, option arguments, and non-option arguments contained in them. Returns 0 if there is not enough memory, else 1 (even if errors are found). In case of error, 'ap_error' returns a non-null pointer.

-- Function: void ap_free ( Arg_parser * const ap )

Frees all dynamically allocated data structures.

-- Function: const char * ap_error ( const Arg_parser * const ap )

Use this funtion to check that the arguments have been correctly parsed by 'ap_init'. If there was an error parsing the arguments, 'ap_error' returns a pointer to an error message explaining the cause, else it returns a null pointer.

-- Function: int ap_argv_index ( const Arg_parser * const ap )

Return the index in argv of the first argument skipped (the first non-option argument) when flags was set to 'ap_in_order_skip'. If no arguments were skipped, argc is returned instead.

4.2 Reading the options and arguments parsed

After a successful call to 'ap_init', which must be checked by calling 'ap_error', the options and arguments parsed can be accessed by means of the following functions:

-- Function: int ap_arguments ( const Arg_parser * const ap )

This function returns the number of options and non-option arguments parsed. This number is usually different from argc.

-- Function: int ap_code ( const Arg_parser * const ap, const int i )

This function returns the code of the option at position i. Valid values for i range from 0 to 'ap_arguments() - 1'. If the code returned is nonzero, 'ap_argument(i)' is the option's argument (or is empty if the option does not have an argument). If the code returned is zero, 'ap_argument(i)' is a non-option argument.

-- Function: const char * ap_parsed_name ( const Arg_parser * const ap, const int i )

This function returns the full name of the option parsed (short or long) at position i. It may be useful to produce more accurate diagnostic messages. For non-option arguments it returns the empty string.

-- Function: const char * ap_argument ( const Arg_parser * const ap, const int i )

This function returns the argument at position i. It may be the argument of an option or a non-option argument, depending on the value returned by 'ap_code(i)'. Valid values for i range from 0 to 'ap_arguments() - 1'. If the argument does not exist, the empty string is returned.

When you are finished, you should free all dynamically allocated data structures by calling 'ap_free'.


Next: , Previous: C version, Up: Top

5 Tutorial for the C++ version

This tutorial uses lzip as an example of how to use Arg_parser in a C++ program. You need to follow these 6 steps:

First copy the files arg_parser.h and arg_parser.cc in your source tree, in the same directory as the file containing the function 'main' of your program. In lzip, 'main' is in main.cc.

Second, include these header files near the top of main.cc:

#include <string>
#include <vector>
#include "arg_parser.h"

Third, define inside 'main' the option names and argument requirements. Lzip defines the following options:

  const Arg_parser::Option options[] = {
    { '0', "fast",              Arg_parser::no  },
    { '1', 0,                   Arg_parser::no  },
    { '2', 0,                   Arg_parser::no  },
    { '3', 0,                   Arg_parser::no  },
    { '4', 0,                   Arg_parser::no  },
    { '5', 0,                   Arg_parser::no  },
    { '6', 0,                   Arg_parser::no  },
    { '7', 0,                   Arg_parser::no  },
    { '8', 0,                   Arg_parser::no  },
    { '9', "best",              Arg_parser::no  },
    { 'a', "trailing-error",    Arg_parser::no  },
    { 'b', "member-size",       Arg_parser::yes },
    { 'c', "stdout",            Arg_parser::no  },
    { 'd', "decompress",        Arg_parser::no  },
    { 'f', "force",             Arg_parser::no  },
    { 'F', "recompress",        Arg_parser::no  },
    { 'h', "help",              Arg_parser::no  },
    { 'k', "keep",              Arg_parser::no  },
    { 'l', "list",              Arg_parser::no  },
    { 'm', "match-length",      Arg_parser::yes },
    { 'n', "threads",           Arg_parser::yes },
    { 'o', "output",            Arg_parser::yes },
    { 'q', "quiet",             Arg_parser::no  },
    { 's', "dictionary-size",   Arg_parser::yes },
    { 'S', "volume-size",       Arg_parser::yes },
    { 't', "test",              Arg_parser::no  },
    { 'v', "verbose",           Arg_parser::no  },
    { 'V', "version",           Arg_parser::no  },
    { opt_lt, "loose-trailing", Arg_parser::no  },
    { 0, 0,                     Arg_parser::no  } };

Fourth, declare and initialize the parser:

  const Arg_parser parser( argc, argv, options );
  if( parser.error().size() )				// bad option
    { show_error( parser.error().c_str(), 0, true ); return 1; }

Fifth, perform the actions corresponding to each option parsed. Lzip performs the following actions:

  int argind = 0;
  for( ; argind < parser.arguments(); ++argind )
    {
    const int code = parser.code( argind );
    if( !code ) break;					// no more options
    const char * const pn = parser.parsed_name( argind ).c_str();
    const std::string & sarg = parser.argument( argind );
    const char * const arg = sarg.c_str();
    switch( code )
      {
      case '0': case '1': case '2': case '3': case '4': case '5':
      case '6': case '7': case '8': case '9': zero = code == '0';
                encoder_options = option_mapping[code-'0']; break;
      case 'a': cl_opts.ignore_trailing = false; break;
      case 'b': member_size = getnum(arg, pn, 100000, max_member_size); break;
      case 'c': to_stdout = true; break;
      case 'd': set_mode( program_mode, m_decompress ); break;
      case 'f': force = true; break;
      case 'F': recompress = true; break;
      case 'h': show_help(); return 0;
      case 'k': keep_input_files = true; break;
      case 'l': set_mode( program_mode, m_list ); break;
      case 'm': encoder_options.match_len_limit =
                  getnum( arg, pn, min_match_len_limit, max_match_len );
                zero = false; break;
      case 'n': break;					// ignored
      case 'o': if( sarg == "-" ) to_stdout = true;
                else { default_output_filename = sarg; } break;
      case 'q': verbosity = -1; break;
      case 's': encoder_options.dictionary_size = get_dict_size( arg, pn );
                zero = false; break;
      case 'S': volume_size = getnum(arg, pn, 100000, max_volume_size); break;
      case 't': set_mode( program_mode, m_test ); break;
      case 'v': if( verbosity < 4 ) ++verbosity; break;
      case 'V': show_version(); return 0;
      case opt_lt: cl_opts.loose_trailing = true; break;
      default: internal_error( "uncaught option." );
      }
    } // end process options

Sixth, process any remaining non-option arguments (file names in the case of lzip):

  std::vector< std::string > filenames;
  bool filenames_given = false;
  for( ; argind < parser.arguments(); ++argind )
    {
    filenames.push_back( parser.argument( argind ) );
    if( filenames.back() != "-" ) filenames_given = true;
    }
  if( filenames.empty() ) filenames.push_back("-");
  // do something with 'filenames'


Next: , Previous: C++ example, Up: Top

6 Tutorial for the C version

This tutorial uses GNU ed as an example of how to use Arg_parser in a C program. You need to follow these 6 steps:

First copy the files carg_parser.h and carg_parser.c in your source tree, in the same directory as the file containing the function 'main' of your program. In GNU ed, 'main' is in main.c.

Second, include the header carg_parser.h near the top of main.c:

#include "carg_parser.h"

Third, define inside 'main' the option names and argument requirements. Ed defines the following options:

  const ap_Option options[] = {
    { 'E', "extended-regexp",      ap_no  },
    { 'G', "traditional",          ap_no  },
    { 'h', "help",                 ap_no  },
    { 'l', "loose-exit-status",    ap_no  },
    { 'p', "prompt",               ap_yes },
    { 'q', "quiet",                ap_no  },
    { 'q', "silent",               ap_no  },
    { 'r', "restricted",           ap_no  },
    { 's', "script",               ap_no  },
    { 'v', "verbose",              ap_no  },
    { 'V', "version",              ap_no  },
    { opt_cr, "strip-trailing-cr", ap_no  },
    { opt_un, "unsafe-names",      ap_no  },
    { 0, 0,                        ap_no  } };

Fourth, declare and initialize the parser:

  Arg_parser parser;
  if( !ap_init( &parser, argc, argv, options, 0 ) )
    { show_error( "Memory exhausted.", 0, false ); return 1; }
  if( ap_error( &parser ) )				/* bad option */
    { show_error( ap_error( &parser ), 0, true ); return 1; }

Fifth, perform the actions corresponding to each option parsed. Ed performs the following actions:

  int argind = 0;
  for( ; argind < ap_arguments( &parser ); ++argind )
    {
    const int code = ap_code( &parser, argind );
    if( !code ) break;				/* no more options */
    const char * const arg = ap_argument( &parser, argind );
    switch( code )
      {
      case 'E': extended_regexp_ = true; break;
      case 'G': traditional_ = true; break;	/* backward compatibility */
      case 'h': show_help(); return 0;
      case 'l': loose = true; break;
      case 'p': if( set_prompt( arg ) ) break; else return 1;
      case 'q': quiet = true; break;
      case 'r': restricted_ = true; break;
      case 's': scripted_ = true; break;
      case 'v': set_verbose(); break;
      case 'V': show_version(); return 0;
      case opt_cr: strip_cr_ = true; break;
      case opt_un: safe_names = false; break;
      default: show_error( "internal error: uncaught option.", 0, false );
               return 3;
      }
    } /* end process options */

Sixth, process any remaining non-option arguments (line number and file name in the case of ed):

  for( ; argind < ap_arguments( &parser ); ++argind )
    {
    const char * const arg = ap_argument( &parser, argind );
    /* do something with 'arg' */
    }


Next: , Previous: C example, Up: Top

7 Reporting bugs

There are probably bugs in Arg_parser. There are certainly errors and omissions in this manual. If you report them, they will get fixed. If you don't, no one will ever know about them and they will remain unfixed for all eternity, if not longer.

If you find a bug in Arg_parser, please send electronic mail to arg-parser-bug@nongnu.org. Include the version number, which you can find by running 'arg_parser --version'.


Next: , Previous: Problems, Up: Top

Concept index


Previous: Concept index, Up: Top

Index of constants and variables


Index of functions