Next: , Previous: gc, Up: Top


29 getopt

     %--------------------------------------------------%
     % vim: ft=mercury ts=4 sw=4 et
     %--------------------------------------------------%
     % Copyright (C) 1994-1999,2001-2007, 2011 The University of Melbourne.
     % This file may only be copied under the terms of the GNU Library General
     % Public License - see the file COPYING in the Mercury distribution.
     %--------------------------------------------------%
     %
     % File: getopt.m.
     % Authors: fjh, zs.
     % Stability: medium.
     %
     % This module exports the predicate getopt.process_options/4, which can be
     % used to parse command-line options.
     %
     % This version allows both short (single-character) options and GNU-style long
     % options. It also has the GNU extension of recognizing options anywhere in
     % the command-line, not just at the start.
     %
     % To use this module, you must provide an `option' type which
     % is an enumeration of all your different options.
     % You must provide predicates `short_option(Char, Option)'
     % and `long_option(String, Option)' which convert the short
     % and/or long names for the option to this enumeration type.
     % (An option can have as many names as you like, long or short.)
     % You must provide a predicate `option_default(Option, OptionData)'
     % which specifies both the type and the default value for every option.
     % You may optionally provide a predicate `special_handler(Option,
     % SpecialData, OptionTable, MaybeOptionTable)' for handling special
     % option types.  (See below.)
     %
     % We support the following "simple" option types:
     %
     %   - bool
     %   - int
     %   - maybe_int (which have a value of `no' or `yes(int)')
     %   - string
     %   - maybe_string (which have a value of `no' or `yes(string)')
     %
     % We also support one "accumulating" option type:
     %
     %   - accumulating (which accumulates a list of strings)
     %
     % And the following "special" option types:
     %
     %   - special
     %   - bool_special
     %   - int_special
     %   - string_special
     %   - maybe_string_special
     %
     % A further special option, file_special, is supported only by the getopt_io
     % module, because it requires process_options to take a pair of I/O state
     % arguments.
     %
     % For the "simple" option types, if there are multiple occurrences of the same
     % option on the command-line, then the last (right-most) occurrence will take
     % precedence.  For "accumulating" options, multiple occurrences will be
     % appended together into a list.
     %
     % The "special" option types are handled by a special option handler (see
     % `special_handler' below), which may perform arbitrary modifications to the
     % option_table.  For example, an option which is not yet implemented could be
     % handled by a special handler which produces an error report, or an option
     % which is a synonym for a set of more "primitive" options could be handled by
     % a special handler which sets those "primitive" options.
     %
     % It is an error to use a "special" option for which there is no handler, or
     % for which the handler fails.
     %
     % Boolean (i.e. bool or bool_special), maybe_int, maybe_string
     % and accumulating options can be negated. Negating an accumulating
     % option empties the accumulated list of strings.
     % Single-character options can be negated by following them
     % with another `-', e.g. `-x-' will negate the `-x' option.
     % Long options can be negated by preceding them with `--no-',
     % e.g. `--no-foo' will negate the `--foo' option.
     %
     % Note that arguments following an option may be separated from the option by
     % either whitespace or an equals, `=', character, e.g. `--foo 3' and `--foo=3'
     % both specify the option `--foo' with the integer argument `3'.
     %
     % If the argument `--' is encountered on the command-line then option
     % processing will immediately terminate, without processing any remaining
     % options.
     %
     %--------------------------------------------------%
     %--------------------------------------------------%
     
     :- module getopt.
     :- interface.
     
     :- import_module bool.
     :- import_module char.
     :- import_module list.
     :- import_module map.
     :- import_module maybe.
     :- import_module set.
     
     % getopt.process_options(OptionOps, Args, NonOptionArgs, Result)
     % getopt.process_options(OptionOps, Args, OptionArgs, NonOptionArgs, Result)
     %
     %   Scans through 'Args' looking for options, places all the option
     %   arguments in `OptionArgs', places all the non-option arguments in
     %   'NonOptionArgs', and records the options in the `OptionTable'.
     %   `OptionTable' is a map from a user-defined option type to option_data.
     %   If an invalid option is encountered, we return `error(Message)'
     %   otherwise we return `ok(OptionTable)' in 'Result'.
     %
     %   The argument `OptionOps' is a structure holding three or four
     %   predicates used to categorize a set of options. Their
     %   interfaces should be like these:
     %
     % :- pred short_option(char::in, option::out) is semidet.
     %   True if the character names a valid single-character option.
     %
     % :- pred long_option(string::in, option::out) is semidet.
     %   True if the character names a valid long option.
     %
     % :- pred option_default(option::out, option_data::out) is multi.
     %   Nondeterministically returns all the options with their
     %   corresponding types and default values.
     %
     % :- pred special_handler(option::in, special_data::in,
     %   option_table::in, maybe_option_table(_)::out) is semidet.
     %   This predicate is invoked whenever getopt finds an option
     %   (long or short) designated as special, with special_data holding
     %   the argument of the option (if any). The predicate can change the
     %   option table in arbitrary ways in the course of handling the option,
     %   or it can return an error message.
     %   The canonical examples of special options are -O options in compilers,
     %   which set many other options at once.
     
     :- pred getopt.process_options(option_ops(OptionType)::in(option_ops),
         list(string)::in, list(string)::out,
         maybe_option_table(OptionType)::out) is det.
     
     :- pred getopt.process_options(option_ops(OptionType)::in(option_ops),
         list(string)::in, list(string)::out, list(string)::out,
         maybe_option_table(OptionType)::out) is det.
     
     % getopt.process_options_track(OptionOps, Args, OptionArgs,
     %       NonOptionArgs, OptionTable0, Result, OptionsSet)
     
     :- pred getopt.process_options_track(
         option_ops_track(OptionType)::in(option_ops_track),
         list(string)::in, list(string)::out, list(string)::out,
         option_table(OptionType)::in, maybe_option_table(OptionType)::out,
         set(OptionType)::out) is det.
     
     :- pred init_option_table(
         pred(OptionType, option_data)::in(pred(out, out) is nondet),
         option_table(OptionType)::out) is det.
     
     :- pred init_option_table_multi(
         pred(OptionType, option_data)::in(pred(out, out) is multi),
         option_table(OptionType)::out) is det.
     
     :- type option_ops(OptionType)
         --->    option_ops(
                     pred(char, OptionType),         % short_option
                     pred(string, OptionType),       % long_option
                     pred(OptionType, option_data)   % option_default
                 )
         ;       option_ops(
                     pred(char, OptionType),         % short_option
                     pred(string, OptionType),       % long_option
                     pred(OptionType, option_data),  % option_default
                     pred(OptionType, special_data,  % special option handler
                         option_table(OptionType),
                         maybe_option_table(OptionType))
                 )
         ;       option_ops_multi(
                     pred(char, OptionType),         % short_option
                     pred(string, OptionType),       % long_option
                     pred(OptionType, option_data)   % option_default
                 )
         ;       option_ops_multi(
                     pred(char, OptionType),         % short_option
                     pred(string, OptionType),       % long_option
                     pred(OptionType, option_data),  % option_default
                     pred(OptionType, special_data,  % special option handler
                         option_table(OptionType),
                         maybe_option_table(OptionType))
                 ).
     
     :- type option_ops_track(OptionType)
         --->    option_ops_track(
                     pred(char, OptionType),         % short_option
                     pred(string, OptionType),       % long_option
                     pred(OptionType, special_data,  % special option handler
                         option_table(OptionType),
                         maybe_option_table(OptionType),
                         set(OptionType))
                 ).
     
     :- inst option_ops ==
         bound((
             option_ops(
                 pred(in, out) is semidet,               % short_option
                 pred(in, out) is semidet,               % long_option
                 pred(out, out) is nondet                % option_default
             )
         ;   option_ops_multi(
                 pred(in, out) is semidet,               % short_option
                 pred(in, out) is semidet,               % long_option
                 pred(out, out) is multi                 % option_default
             )
         ;   option_ops(
                 pred(in, out) is semidet,               % short_option
                 pred(in, out) is semidet,               % long_option
                 pred(out, out) is nondet,               % option_default
                 pred(in, in, in, out) is semidet        % special handler
             )
         ;   option_ops_multi(
                 pred(in, out) is semidet,               % short_option
                 pred(in, out) is semidet,               % long_option
                 pred(out, out) is multi,                % option_default
                 pred(in, in, in, out) is semidet        % special handler
             )
         )).
     
     :- inst option_ops_track ==
         bound((
             option_ops_track(
                 pred(in, out) is semidet,               % short_option
                 pred(in, out) is semidet,               % long_option
                 pred(in, in, in, out, out) is semidet   % special handler
             )
         )).
     
     :- type option_data
         --->    bool(bool)
         ;       int(int)
         ;       string(string)
         ;       maybe_int(maybe(int))
         ;       maybe_string(maybe(string))
         ;       accumulating(list(string))
         ;       special
         ;       bool_special
         ;       int_special
         ;       string_special
         ;       maybe_string_special.
     
     :- type special_data
         --->    none
         ;       bool(bool)
         ;       int(int)
         ;       string(string)
         ;       maybe_string(maybe(string)).
     
     :- type option_table(OptionType) ==  map(OptionType, option_data).
     
     :- type maybe_option_table(OptionType)
         --->    ok(option_table(OptionType))
         ;       error(string).
     
         % The following three predicates search the option table for
         % an option of the specified type; if it is not found, they
         % report an error by calling error/1.
     
     :- pred getopt.lookup_bool_option(option_table(Option)::in, Option::in,
         bool::out) is det.
     :- func getopt.lookup_bool_option(option_table(Option), Option) = bool.
     
     :- pred getopt.lookup_int_option(option_table(Option)::in, Option::in,
         int::out) is det.
     :- func getopt.lookup_int_option(option_table(Option), Option) = int.
     
     :- pred getopt.lookup_string_option(option_table(Option)::in, Option::in,
         string::out) is det.
     :- func getopt.lookup_string_option(option_table(Option), Option) = string.
     
     :- pred getopt.lookup_maybe_int_option(option_table(Option)::in, Option::in,
         maybe(int)::out) is det.
     :- func getopt.lookup_maybe_int_option(option_table(Option), Option) =
         maybe(int).
     
     :- pred getopt.lookup_maybe_string_option(option_table(Option)::in,
         Option::in, maybe(string)::out) is det.
     :- func getopt.lookup_maybe_string_option(option_table(Option), Option) =
         maybe(string).
     
     :- pred getopt.lookup_accumulating_option(option_table(Option)::in,
         Option::in, list(string)::out) is det.
     :- func getopt.lookup_accumulating_option(option_table(Option), Option) =
         list(string).
     
     %--------------------------------------------------%
     %--------------------------------------------------%