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.
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.
'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.
POSIX recommends these conventions for command-line arguments. Arg_parser makes it easy to implement them.
Arg_parser normally makes it appear as if all the options were specified before all the non-option arguments for the purposes of parsing, even if the user of your program intermixed options and non-option arguments. If you want the arguments in the exact order the user typed them, call 'Arg_parser' with flags = 'in_order'.
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>="".
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.
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.
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:intcode
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_arghas_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.
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:Flagsin_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:Flagsin_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:Flagsin_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:Flagsneg_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.
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.
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.
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.
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.
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:
This function returns the number of options and non-option arguments parsed. This number is usually different from argc.
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.
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.
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.
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.
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.
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.
Frees all dynamically allocated data structures.
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.
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.
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:
This function returns the number of options and non-option arguments parsed. This number is usually different from argc.
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.
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.
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'.
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'
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' */
}
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'.
code: C++ versionhas_arg: C++ versionin_order: C++ versionin_order_skip: C++ versionin_order_stop: C++ versionlong_name: C++ versionneg_non_opt: C++ versionap_argument: C versionap_arguments: C versionap_argv_index: C versionap_code: C versionap_error: C versionap_free: C versionap_init: C versionap_parsed_name: C versionArg_parser: C++ versionargument: C++ versionarguments: C++ versionargv_index: C++ versioncode: C++ versionerror: C++ versionparsed_name: C++ version