\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename arg_parser.info
@documentencoding ISO-8859-15
@settitle Arg_parser Manual
@finalout
@paragraphindent 0
@c %**end of header

@set UPDATED 29 June 2025
@set VERSION 1.20

@dircategory Libraries
@direntry
* Arg_parser: (arg_parser).     A POSIX/GNU command-line argument parser
@end direntry


@ifnothtml
@titlepage
@title Arg_parser
@subtitle A POSIX/GNU command-line argument parser
@subtitle for Arg_parser version @value{VERSION}, @value{UPDATED}
@author by Antonio Diaz Diaz

@page
@vskip 0pt plus 1filll
@end titlepage

@contents
@end ifnothtml

@ifnottex
@node Top
@top

This manual is for Arg_parser (version @value{VERSION}, @value{UPDATED}).

@menu
* Introduction::        Purpose and features of Arg_parser
* Argument syntax::     By convention, options start with a hyphen
* C++ version::         Using the C++ version of Arg_parser
* C version::           Using the C version of Arg_parser
* C++ example::         Tutorial for the C++ version
* C example::           Tutorial for the C version
* Problems::            Reporting bugs
* Concept index::       Index of concepts
@end menu

@sp 1
Copyright @copyright{} 2006-2025 Antonio Diaz Diaz.

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


@node Introduction
@chapter Introduction
@cindex introduction

@uref{http://www.nongnu.org/arg-parser/arg_parser.html,,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 @samp{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
@uref{http://www.gnu.org/software/moe/moe.html,,GNU moe}, because moe's
argument parsing is rather complex. Then I used it in my other projects,
including
@uref{http://www.gnu.org/software/ddrescue/ddrescue.html,,GNU ddrescue},
@uref{http://www.gnu.org/software/ed/ed.html,,GNU ed},
@uref{http://www.nongnu.org/lzip/lzip.html,,lzip},
@uref{http://www.gnu.org/software/ocrad/ocrad.html,,GNU ocrad},
@uref{http://www.nongnu.org/lzip/tarlz.html,,tarlz}, and
@uref{http://www.nongnu.org/zutils/zutils.html,,zutils}, with excellent
results.


@node Argument syntax
@chapter Syntax of command-line arguments
@cindex argument syntax

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

@itemize @bullet
@item A command-line argument is an option if it begins with a hyphen
(@samp{-}).

@item Option names are single alphanumeric characters.

@item Certain options require an argument.

@item An option and its argument may or may not appear as separate tokens.
(In other words, the whitespace separating them is optional, unless the
argument is the empty string).
Thus, @w{@option{-o foo}} and @option{-ofoo} are equivalent.

@item One or more options without arguments, followed by at most one option
that takes an argument, may follow a hyphen in a single token.
Thus, @option{-abc} is equivalent to @w{@option{-a -b -c}}.

@item Options typically precede other non-option arguments.

Arg_parser normally makes it appear as if all the option arguments were
specified before all the non-option arguments for the purposes of parsing,
even if the user of your program intermixed option and non-option arguments.
If you want the arguments in the exact order the user typed them, call
@samp{Arg_parser} with @w{@var{in_order} = true}.

@item The argument @samp{--} terminates all options; any following arguments
are treated as non-option arguments, even if they begin with a hyphen.

@item A token consisting of a single hyphen character is interpreted as an
ordinary non-option argument. By convention, it is used to specify standard
input, standard output, or a file named @samp{-}.

@item Options may be supplied in any order, or appear multiple times.
The interpretation is left up to the particular application program.
@end itemize

GNU adds @dfn{long options} to these conventions:

@itemize @bullet
@item A long option consists of two hyphens (@samp{--}) followed by a name
made of alphanumeric characters and hyphens. Option names are typically one
to three words long, with hyphens to separate words. Abbreviations can be
used for the long option names as long as the abbreviations are unique.

@item A long option and its argument may or may not appear as separate
tokens. In the latter case they must be separated by an equal sign @samp{=}.
Thus, @w{@option{--foo bar}} and @option{--foo=bar} are equivalent.
@end itemize

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

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


@node C++ version
@chapter Using the C++ version of Arg_parser
@cindex C++ version

The C++ version of Arg_parser is provided in the files @file{arg_parser.h}
and @file{arg_parser.cc}. To learn how to use Arg_parser in your C++
programs, @pxref{C++ example}, and the file @file{main.cc} in the
@uref{http://download.savannah.nongnu.org/releases/arg-parser/,,source tarball}.

@section Parsing arguments and reporting errors

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

@anchor{struct Option}
@deftp {Data Type} struct Option
This structure describes a single option for the sake of @samp{Arg_parser}.
The argument @var{options} must be an array of these structures, one for
each option. Terminate the array with an element containing a code which is
zero. @samp{struct Option} has the following members:

@table @code
@item 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.

@item 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.

@item enum Has_arg has_arg
This member says whether the option takes an argument. It has four valid
values: @samp{no}, @samp{yes}, @samp{maybe}, and @samp{yme}, meaning
respectively @samp{no argument}, @samp{non-empty argument required},
@samp{optional argument}, and @samp{argument required, but it may be the
empty string}. @samp{yme} is not recommended.

If an empty argument is passed to an option specified as @samp{yme}, it must
be in a separate command-line argument or specified as a long option with
the empty string after the @samp{=} character. It can't be specified as the
empty string after the short option.
@end table
@end deftp

@defun Arg_parser ( const int @var{argc}, const char * const @var{argv}[], const Option @var{options}[], const bool @var{in_order} = false )
Constructor. Reads the arguments in @var{argv} and parses all options,
option arguments, and non-option arguments contained in them. In case of
error, @samp{error().size()} returns nonzero.
@end defun

@defun Arg_parser ( const char * const @var{opt}, const char * const @var{arg}, const Option @var{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,
@samp{error().size()} returns nonzero.
@end defun

@deftypefun {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, @samp{error}
returns an error message explaining the cause.
@end deftypefun

@section Reading the options and arguments parsed

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

@deftypefun int arguments () const
This function returns the number of options and non-option arguments parsed.
This number is usually different from argc.
@end deftypefun

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

@deftypefun {const std::string &} parsed_name ( const int @var{i} ) const
This function returns the full name of the option parsed (short or long) at
position @var{i}. It may be useful to produce more accurate diagnostic
messages. For non-option arguments it returns the empty string.
@end deftypefun

@deftypefun {const std::string &} argument ( const int @var{i} ) const
This function returns the argument at position @var{i}. It may be the
argument of an option or a non-option argument, depending on the value
returned by @samp{code(@var{i})}. Valid values for @var{i} range from 0 to
@w{@samp{arguments() - 1}}. If the argument does not exist, the empty string
is returned.
@end deftypefun


@node C version
@chapter Using the C version of Arg_parser
@cindex C version

The C version of Arg_parser is provided in the files @file{carg_parser.h}
and @file{carg_parser.c}. To learn how to use Arg_parser in your C programs,
@pxref{C example}, and the file @file{cmain.c} in the
@uref{http://download.savannah.nongnu.org/releases/arg-parser/,,source tarball}.

@section Parsing arguments and reporting errors

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

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

@deftypefun char ap_init ( Arg_parser * const @var{ap}, const int @var{argc}, const char * const @var{argv}[], const ap_Option @var{options}[], const char @var{in_order} )
Reads the arguments in @var{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, @samp{ap_error}
returns a non-null pointer.
@end deftypefun

@deftypefun void ap_free ( Arg_parser * const @var{ap} )
Frees all dynamically allocated data structures.
@end deftypefun

@deftypefun {const char *} ap_error ( const Arg_parser * const @var{ap} )
Use this funtion to check that the arguments have been correctly parsed by
@samp{ap_init}. If there was an error parsing the arguments, @samp{ap_error}
returns a pointer to an error message explaining the cause, else it returns
a null pointer.
@end deftypefun

@section Reading the options and arguments parsed

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

@deftypefun int ap_arguments ( const Arg_parser * const @var{ap} )
This function returns the number of options and non-option arguments parsed.
This number is usually different from argc.
@end deftypefun

@deftypefun int ap_code ( const Arg_parser * const @var{ap}, const int @var{i} )
This function returns the code of the option at position @var{i}. Valid
values for @var{i} range from 0 to @w{@samp{ap_arguments() - 1}}. If the
code returned is nonzero, @samp{ap_argument(@var{i})} is the option's
argument (or is empty if the option does not have an argument). If the code
returned is zero, @samp{ap_argument(@var{i})} is a non-option argument.
@end deftypefun

@deftypefun {const char *} ap_parsed_name ( const Arg_parser * const @var{ap}, const int @var{i} )
This function returns the full name of the option parsed (short or long) at
position @var{i}. It may be useful to produce more accurate diagnostic
messages. For non-option arguments it returns the empty string.
@end deftypefun

@deftypefun {const char *} ap_argument ( const Arg_parser * const @var{ap}, const int @var{i} )
This function returns the argument at position @var{i}. It may be the
argument of an option or a non-option argument, depending on the value
returned by @samp{ap_code(@var{i})}. Valid values for @var{i} range from 0
to @w{@samp{ap_arguments() - 1}}. If the argument does not exist, the empty
string is returned.
@end deftypefun

When you are finished, you should free all dynamically allocated data
structures by calling @samp{ap_free}.


@node C++ example
@chapter Tutorial for the C++ version
@cindex C++ example

This tutorial uses @uref{http://www.nongnu.org/lzip/lzip.html,,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 @file{arg_parser.h} and @file{arg_parser.cc} in your
source tree, in the same directory as the file containing the function
@samp{main} of your program. In lzip, @samp{main} is in @file{main.cc}.

Second, include these header files near the top of @file{main.cc}:

@verbatim
#include <string>
#include <vector>
#include "arg_parser.h"
@end verbatim

Third, define inside @samp{main} the option names and argument requirements.
Lzip defines the following options:

@verbatim
  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  } };
@end verbatim

Fourth, declare and initialize the parser:

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

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

@verbatim
  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
@end verbatim

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

@verbatim
  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'
@end verbatim


@node C example
@chapter Tutorial for the C version
@cindex C example

This tutorial uses @uref{http://www.gnu.org/software/ed/ed.html,,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 @file{carg_parser.h} and @file{carg_parser.c} in your
source tree, in the same directory as the file containing the function
@samp{main} of your program. In GNU ed, @samp{main} is in @file{main.c}.

Second, include the header @file{carg_parser.h} near the top of @file{main.c}:

@verbatim
#include "carg_parser.h"
@end verbatim

Third, define inside @samp{main} the option names and argument requirements.
Ed defines the following options:

@verbatim
  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  } };
@end verbatim

Fourth, declare and initialize the parser:

@verbatim
  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; }
@end verbatim

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

@verbatim
  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 */
@end verbatim

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

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


@node Problems
@chapter Reporting bugs
@cindex bugs
@cindex getting help

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
@email{arg-parser-bug@@nongnu.org}. Include the version number, which
you can find by running @w{@samp{arg_parser --version}}.


@node Concept index
@unnumbered Concept index

@printindex cp

@bye
