View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2002-2021, University of Amsterdam
    7                              VU University Amsterdam
    8                              SWI-Prolog Solutions b.v.
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module(prolog_main,
   38          [ main/0,
   39            argv_options/3,             % +Argv, -RestArgv, -Options
   40            argv_options/4,             % +Argv, -RestArgv, -Options, +ParseOpts
   41            argv_usage/1,               % +Level
   42            cli_parse_debug_options/2,  % +OptionsIn, -Options
   43            cli_enable_development_system/0
   44          ]).   45% use autoload/1 to avoid checking these files at load time.
   46:- autoload(library(debug)).   47:- autoload(library(threadutil)).   48% These are fine to be checked and loaded
   49:- autoload(library(apply), [maplist/3, partition/4]).   50:- autoload(library(lists), [append/3]).   51:- autoload(library(pairs), [pairs_keys/2, pairs_values/2]).   52:- autoload(library(prolog_code), [pi_head/2]).   53:- autoload(library(prolog_debug), [spy/1]).   54:- autoload(library(dcg/high_order), [sequence//3, sequence//2]).   55:- autoload(library(option), [option/2]).   56
   57:- meta_predicate
   58    argv_options(:, -, -),
   59    argv_options(:, -, -, +),
   60    argv_usage(:).   61
   62:- dynamic
   63    interactive/0.

Provide entry point for scripts

This library is intended for supporting PrologScript on Unix using the #! magic sequence for scripts using commandline options. The entry point main/0 calls the user-supplied predicate main/1 passing a list of commandline options. Below is a simle echo implementation in Prolog.

#!/usr/bin/env swipl

:- initialization(main, main).

main(Argv) :-
    echo(Argv).

echo([]) :- nl.
echo([Last]) :- !,
    write(Last), nl.
echo([H|T]) :-
    write(H), write(' '),
    echo(T).
See also
- library(prolog_stack) to force backtraces in case of an uncaught exception.
- XPCE users should have a look at library(pce_main), which starts the GUI and processes events until all windows have gone. */
   94:- module_transparent
   95    main/0.
 main
Call main/1 using the passed command-line arguments. Before calling main/1 this predicate installs a signal handler for SIGINT (Control-C) that terminates the process with status 1.
  103main :-
  104    context_module(M),
  105    set_signals,
  106    current_prolog_flag(argv, Av),
  107    catch_with_backtrace(M:main(Av), Error, throw(Error)),
  108    (   interactive
  109    ->  cli_enable_development_system
  110    ;   true
  111    ).
  112
  113set_signals :-
  114    on_signal(int, _, interrupt).
 interrupt(+Signal)
We received an interrupt. This handler is installed using on_signal/3.
  121interrupt(_Sig) :-
  122    halt(1).
  123
  124		 /*******************************
  125		 *            OPTIONS		*
  126		 *******************************/
 argv_options(:Argv, -Positional, -Options) is det
Parse command line arguments. This predicate acts in one of two modes.

When guided, three predicates are called in the calling module. opt_type/3 must be defined, the others need not. Note that these three predicates may be defined as multifile to allow multiple modules contributing to the provided commandline options. Defining them as discontiguous allows for creating blocks that describe a group of related options.

opt_type(Opt, Name, Type)
Defines Opt to add an option Name(Value), where Value statisfies Type. Opt does not include the leading -. A single character implies a short option, multiple a long option. Long options use _ as word separator, user options may use either _ or -. Type is one of:
A | B
Disjunctive type.
boolean(Default)
boolean
Boolean options are special. They do not take a value except for when using the long --opt=value notation. This explicit value specification converts true, True, TRUE, on, On, ON, 1 and the obvious false equivalents to Prolog true or false. If the option is specified, Default is used. If --no-opt or --noopt is used, the inverse of Default is used.
integer
Argument is converted to an integer
float
Argument is converted to a float. User may specify an integer
nonneg
As integer. Requires value >= 0.
natural
As integer. Requires value >= 1.
number
Any number (integer, float, rational).
between(Low, High)
If both one of Low and High is a float, convert as float, else convert as integer. Then check the range.
atom
No conversion
oneof(List)
As atom, but requires the value to be a member of List (enum type).
string
Convert to a SWI-Prolog string
file
Convert to a file name in Prolog canonical notation using prolog_to_os_filename/2.
file(Access)
As file, and check access using access_file/2. A value - is not checked for access, assuming the application handles this as standard input or output.
term
Parse option value to a Prolog term.
term(+Options)
As term, but passes Options to term_string/3. If the option variable_names(Bindings) is given the option value is set to the pair Term-Bindings.
opt_help(Name, HelpString)
Help string used by argv_usage/1.
opt_meta(Name, Meta)
If a typed argument is required this defines the placeholder in the help message. The default is the uppercase version of the type functor name. This produces the FILE in e.g. -f FILE.

By default, -h, -? and --help are bound to help. If opt_type(Opt, help, boolean) is true for some Opt, the default help binding and help message are disabled and the normal user rules apply. In particular, the user should also provide a rule for opt_help(help, String).

  214argv_options(M:Argv, Positional, Options) :-
  215    in(M:opt_type(_,_,_)),
  216    !,
  217    argv_options(M:Argv, Positional, Options, [on_error(halt(1))]).
  218argv_options(_:Argv, Positional, Options) :-
  219    argv_untyped_options(Argv, Positional, Options).
 argv_options(:Argv, -Positional, -Options, +ParseOptions) is det
As argv_options/3 in guided mode, Currently this version allows parsing argument options throwing an exception rather than calling halt/1 by passing an empty list to ParseOptions. ParseOptions:
on_error(+Goal)
If Goal is halt(Code), exit with Code. Other goals are currently not supported.
options_after_arguments(+Boolean)
If false (default true), stop parsing after the first positional argument, returning options that follow this argument as positional arguments. E.g, -x file -y results in positional arguments [file, '-y']
  236argv_options(Argv, Positional, Options, POptions) :-
  237    option(on_error(halt(Code)), POptions),
  238    !,
  239    E = error(_,_),
  240    catch(opt_parse(Argv, Positional, Options, POptions), E,
  241          ( print_message(error, E),
  242            halt(Code)
  243          )).
  244argv_options(Argv, Positional, Options, POptions) :-
  245    opt_parse(Argv, Positional, Options, POptions).
 argv_untyped_options(+Argv, -RestArgv, -Options) is det
Generic transformation of long commandline arguments to options. Each --Name=Value is mapped to Name(Value). Each plain name is mapped to Name(true), unless Name starts with no-, in which case the option is mapped to Name(false). Numeric option values are mapped to Prolog numbers.
  255argv_untyped_options([], Pos, Opts) =>
  256    Pos = [], Opts = [].
  257argv_untyped_options([--|R], Pos, Ops) =>
  258    Pos = R, Ops = [].
  259argv_untyped_options([H0|T0], R, Ops), sub_atom(H0, 0, _, _, --) =>
  260    Ops = [H|T],
  261    (   sub_atom(H0, B, _, A, =)
  262    ->  B2 is B-2,
  263        sub_atom(H0, 2, B2, _, Name),
  264        sub_string(H0, _, A,  0, Value0),
  265        convert_option(Name, Value0, Value)
  266    ;   sub_atom(H0, 2, _, 0, Name0),
  267        (   sub_atom(Name0, 0, _, _, 'no-')
  268        ->  sub_atom(Name0, 3, _, 0, Name),
  269            Value = false
  270        ;   Name = Name0,
  271            Value = true
  272        )
  273    ),
  274    canonical_name(Name, PlName),
  275    H =.. [PlName,Value],
  276    argv_untyped_options(T0, R, T).
  277argv_untyped_options([H|T0], Ops, T) =>
  278    Ops = [H|R],
  279    argv_untyped_options(T0, R, T).
  280
  281convert_option(password, String, String) :- !.
  282convert_option(_, String, Number) :-
  283    number_string(Number, String),
  284    !.
  285convert_option(_, String, Atom) :-
  286    atom_string(Atom, String).
  287
  288canonical_name(Name, PlName) :-
  289    split_string(Name, "-_", "", Parts),
  290    atomic_list_concat(Parts, '_', PlName).
 opt_parse(:Argv, -Positional, -Options, +POptions) is det
Rules follow those of Python optparse:
  302opt_parse(M:Argv, _Positional, _Options, _POptions) :-
  303    opt_needs_help(M:Argv),
  304    !,
  305    argv_usage(M:debug),
  306    halt(0).
  307opt_parse(M:Argv, Positional, Options, POptions) :-
  308    opt_parse(Argv, Positional, Options, M, POptions).
  309
  310opt_needs_help(M:[Arg]) :-
  311    in(M:opt_type(_, help, boolean)),
  312    !,
  313    in(M:opt_type(Opt, help, boolean)),
  314    (   short_opt(Opt)
  315    ->  atom_concat(-, Opt, Arg)
  316    ;   atom_concat(--, Opt, Arg)
  317    ),
  318    !.
  319opt_needs_help(_:['-h']).
  320opt_needs_help(_:['-?']).
  321opt_needs_help(_:['--help']).
  322
  323opt_parse([], Positional, Options, _, _) =>
  324    Positional = [],
  325    Options = [].
  326opt_parse([--|T], Positional, Options, _, _) =>
  327    Positional = T,
  328    Options = [].
  329opt_parse([H|T], Positional, Options, M, POptions), atom_concat(--, Long, H) =>
  330    take_long(Long, T, Positional, Options, M, POptions).
  331opt_parse([H|T], Positional, Options, M, POptions),
  332    H \== '-',
  333    string_concat(-, Opts, H) =>
  334    string_chars(Opts, Shorts),
  335    take_shorts(Shorts, T, Positional, Options, M, POptions).
  336opt_parse(Argv, Positional, Options, _M, POptions),
  337    option(options_after_arguments(false), POptions) =>
  338    Positional = Argv,
  339    Options = [].
  340opt_parse([H|T], Positional, Options, M, POptions) =>
  341    Positional = [H|PT],
  342    opt_parse(T, PT, Options, M, POptions).
  343
  344
  345take_long(Long, T, Positional, Options, M, POptions) :- % --long=Value
  346    sub_atom(Long, B, _, A, =),
  347    !,
  348    sub_atom(Long, 0, B, _, LName0),
  349    sub_atom(Long, _, A, 0, VAtom),
  350    canonical_name(LName0, LName),
  351    (   in(M:opt_type(LName, Name, Type))
  352    ->  opt_value(Type, Long, VAtom, Value),
  353        Opt =.. [Name,Value],
  354        Options = [Opt|OptionsT],
  355        opt_parse(T, Positional, OptionsT, M, POptions)
  356    ;   opt_error(unknown_option(M:LName0))
  357    ).
  358take_long(LName0, T, Positional, Options, M, POptions) :- % --long
  359    canonical_name(LName0, LName),
  360    take_long_(LName, T, Positional, Options, M, POptions).
  361
  362take_long_(Long, T, Positional, Options, M, POptions) :- % --long
  363    opt_bool_type(Long, Name, Value, M),
  364    !,
  365    Opt =.. [Name,Value],
  366    Options = [Opt|OptionsT],
  367    opt_parse(T, Positional, OptionsT, M, POptions).
  368take_long_(Long, T, Positional, Options, M, POptions) :- % --no-long, --nolong
  369    (   atom_concat('no_', LName, Long)
  370    ;   atom_concat('no', LName, Long)
  371    ),
  372    opt_bool_type(LName, Name, Value0, M),
  373    !,
  374    negate(Value0, Value),
  375    Opt =.. [Name,Value],
  376    Options = [Opt|OptionsT],
  377    opt_parse(T, Positional, OptionsT, M, POptions).
  378take_long_(Long, T, Positional, Options, M, POptions) :- % --long
  379    in(M:opt_type(Long, Name, Type)),
  380    !,
  381    (   T = [VAtom|T1]
  382    ->  opt_value(Type, Long, VAtom, Value),
  383        Opt =.. [Name,Value],
  384        Options = [Opt|OptionsT],
  385        opt_parse(T1, Positional, OptionsT, M, POptions)
  386    ;   opt_error(missing_value(Long, Type))
  387    ).
  388take_long_(Long, _, _, _, M, _) :-
  389    opt_error(unknown_option(M:Long)).
  390
  391take_shorts([], T, Positional, Options, M, POptions) :-
  392    opt_parse(T, Positional, Options, M, POptions).
  393take_shorts([H|T], Argv, Positional, Options, M, POptions) :-
  394    opt_bool_type(H, Name, Value, M),
  395    !,
  396    Opt =.. [Name,Value],
  397    Options = [Opt|OptionsT],
  398    take_shorts(T, Argv, Positional, OptionsT, M, POptions).
  399take_shorts([H|T], Argv, Positional, Options, M, POptions) :-
  400    in(M:opt_type(H, Name, Type)),
  401    !,
  402    (   T == []
  403    ->  (   Argv = [VAtom|ArgvT]
  404        ->  opt_value(Type, H, VAtom, Value),
  405            Opt =.. [Name,Value],
  406            Options = [Opt|OptionsT],
  407            take_shorts(T, ArgvT, Positional, OptionsT, M, POptions)
  408        ;   opt_error(missing_value(H, Type))
  409        )
  410    ;   atom_chars(VAtom, T),
  411        opt_value(Type, H, VAtom, Value),
  412        Opt =.. [Name,Value],
  413        Options = [Opt|OptionsT],
  414        take_shorts([], Argv, Positional, OptionsT, M, POptions)
  415    ).
  416take_shorts([H|_], _, _, _, M, _) :-
  417    opt_error(unknown_option(M:H)).
  418
  419opt_bool_type(Opt, Name, Value, M) :-
  420    in(M:opt_type(Opt, Name, Type)),
  421    (   Type == boolean
  422    ->  Value = true
  423    ;   Type = boolean(Value)
  424    ).
  425
  426negate(true, false).
  427negate(false, true).
 opt_value(+Type, +Opt, +VAtom, -Value) is det
Errors
- opt_error(Error)
  433opt_value(Type, _Opt, VAtom, Value) :-
  434    opt_convert(Type, VAtom, Value),
  435    !.
  436opt_value(Type, Opt, VAtom, _) :-
  437    opt_error(value_type(Opt, Type, VAtom)).
 opt_convert(+Type, +VAtom, -Value) is semidet
  441opt_convert(A|B, Spec, Value) :-
  442    (   opt_convert(A, Spec, Value)
  443    ->  true
  444    ;   opt_convert(B, Spec, Value)
  445    ).
  446opt_convert(boolean, Spec, Value) :-
  447    to_bool(Spec, Value).
  448opt_convert(boolean(_), Spec, Value) :-
  449    to_bool(Spec, Value).
  450opt_convert(number, Spec, Value) :-
  451    atom_number(Spec, Value).
  452opt_convert(integer, Spec, Value) :-
  453    atom_number(Spec, Value),
  454    integer(Value).
  455opt_convert(float, Spec, Value) :-
  456    atom_number(Spec, Value0),
  457    Value is float(Value0).
  458opt_convert(nonneg, Spec, Value) :-
  459    atom_number(Spec, Value),
  460    integer(Value),
  461    Value >= 0.
  462opt_convert(natural, Spec, Value) :-
  463    atom_number(Spec, Value),
  464    integer(Value),
  465    Value >= 1.
  466opt_convert(between(Low, High), Spec, Value) :-
  467    atom_number(Spec, Value0),
  468    (   ( float(Low) ; float(High) )
  469    ->  Value is float(Value0)
  470    ;   integer(Value0),
  471        Value = Value0
  472    ),
  473    Value >= Low, Value =< High.
  474opt_convert(atom, Value, Value).
  475opt_convert(oneof(List), Value, Value) :-
  476    memberchk(Value, List).
  477opt_convert(string, Value0, Value) :-
  478    atom_string(Value0, Value).
  479opt_convert(file, Spec, Value) :-
  480    prolog_to_os_filename(Value, Spec).
  481opt_convert(file(Access), Spec, Value) :-
  482    (   Spec == '-'
  483    ->  Value = '-'
  484    ;   prolog_to_os_filename(Value, Spec),
  485        (   access_file(Value, Access)
  486        ->  true
  487        ;   opt_error(access_file(Spec, Access))
  488        )
  489    ).
  490opt_convert(term, Spec, Value) :-
  491    term_string(Value, Spec, []).
  492opt_convert(term(Options), Spec, Value) :-
  493    term_string(Term, Spec, Options),
  494    (   option(variable_names(Bindings), Options)
  495    ->  Value = Term-Bindings
  496    ;   Value = Term
  497    ).
  498
  499to_bool(true,    true).
  500to_bool('True',  true).
  501to_bool('TRUE',  true).
  502to_bool(on,      true).
  503to_bool('On',    true).
  504to_bool('1',     true).
  505to_bool(false,   false).
  506to_bool('False', false).
  507to_bool('FALSE', false).
  508to_bool(off,     false).
  509to_bool('Off',   false).
  510to_bool('0',     false).
 argv_usage(:Level) is det
Use print_message/2 to print a usage message at Level. To print the message as plain text indefault color, use debug. Other meaningful options are informational or warning. The help page consists of four sections, two of which are optional:
  1. The header is created from opt_help(help(header), String). It is optional.
  2. The usage is added by default. The part behind Usage: <command> is by default [options] and can be overruled using opt_help(help(usage), String).
  3. The actual option descriptions. The options are presented in the order they are defined in opt_type/3. Subsequent options for the same destination (option name) are joined with the first.
  4. The footer_ is created from opt_help(help(footer), String). It is optional.

The help provided by help(header), help(usage) and help(footer) are either a simple string or a list of elements as defined by print_message_lines/3. In the latter case, the construct \Callable can be used to call a DCG rule in the module from which the user calls argv_options/3. For example, we can add a bold title using

opt_help(help(header), [ansi(bold, '~w', ['My title'])]).
  539argv_usage(M:Level) :-
  540    print_message(Level, opt_usage(M)).
  541
  542:- multifile
  543    prolog:message//1.  544
  545prolog:message(opt_usage(M)) -->
  546    usage(M).
  547
  548usage(M) -->
  549    usage_text(M:header),
  550    usage_line(M),
  551    usage_options(M),
  552    usage_text(M:footer).
 usage_text(:Which)// is det
Emit a user element. This may use elements as defined by print_message_lines/3 or can be a simple string.
  559usage_text(M:Which) -->
  560    { in(M:opt_help(help(Which), Help))
  561    },
  562    !,
  563    (   {Which == header}
  564    ->  user_text(M:Help), [nl]
  565    ;   [nl], user_text(M:Help)
  566    ).
  567usage_text(_) -->
  568    [].
  569
  570user_text(M:Entries) -->
  571    { is_list(Entries) },
  572    sequence(help_elem(M), Entries).
  573user_text(_:Help) -->
  574    [ '~w'-[Help] ].
  575
  576help_elem(M, \Callable) -->
  577    { callable(Callable) },
  578    call(M:Callable),
  579    !.
  580help_elem(_M, Elem) -->
  581    [ Elem ].
  582
  583usage_line(M) -->
  584    [ ansi(comment, 'Usage: ', []) ],
  585    cmdline(M),
  586    (   {in(M:opt_help(help(usage), Help))}
  587    ->  user_text(M:Help)
  588    ;   [ ' [options]'-[] ]
  589    ),
  590    [ nl, nl ].
  591
  592cmdline(_M) -->
  593    { current_prolog_flag(associated_file, AbsFile),
  594      file_base_name(AbsFile, Base),
  595      current_prolog_flag(os_argv, Argv),
  596      append(Pre, [File|_], Argv),
  597      file_base_name(File, Base),
  598      append(Pre, [File], Cmd),
  599      !
  600    },
  601    sequence(cmdarg, [' '-[]], Cmd).
  602cmdline(_M) -->
  603    { current_prolog_flag(saved_program, true),
  604      current_prolog_flag(os_argv, OsArgv),
  605      append(_, ['-x', State|_], OsArgv),
  606      !
  607    },
  608    cmdarg(State).
  609cmdline(_M) -->
  610    { current_prolog_flag(os_argv, [Argv0|_])
  611    },
  612    cmdarg(Argv0).
  613
  614cmdarg(A) -->
  615    [ '~w'-[A] ].
 usage_options(+Module)//
Find the defined options and display help on them. Uses opt_type/3 to find the options and their type, opt_help/2 to find the option help comment and opt_meta/2 for meta types.
  623usage_options(M) -->
  624    { findall(Opt, get_option(M, Opt), Opts),
  625      maplist(options_width, Opts, OptWidths),
  626      max_list(OptWidths, MaxOptWidth),
  627      catch(tty_size(_, Width), _, Width = 80),
  628      OptColW is min(MaxOptWidth, 30),
  629      HelpColW is Width-4-OptColW
  630    },
  631    [ ansi(comment, 'Options:', []), nl ],
  632    sequence(opt_usage(OptColW, HelpColW), [nl], Opts).
  633
  634opt_usage(OptColW, HelpColW, opt(_Name, Type, Short, Long, Help, Meta)) -->
  635    options(Type, Short, Long, Meta),
  636    [ '~t~*:| '-[OptColW] ],
  637    help_text(Help, OptColW, HelpColW).
  638
  639help_text([First|Lines], Indent, _Width) -->
  640    !,
  641    [ '~w'-[First], nl ],
  642    sequence(rest_line(Indent), [nl], Lines).
  643help_text(Text, _Indent, Width) -->
  644    { string_length(Text, Len),
  645      Len =< Width
  646    },
  647    !,
  648    [ '~w'-[Text] ].
  649help_text(Text, Indent, Width) -->
  650    { wrap_text(Width, Text, [First|Lines])
  651    },
  652    [ '~w'-[First], nl ],
  653    sequence(rest_line(Indent), [nl], Lines).
  654
  655rest_line(Indent, Line) -->
  656    [ '~t~*| ~w'-[Indent, Line] ].
 wrap_text(+Width, +Text, -Wrapped)
Simple text wrapper. Breaks Text into words and creates lines with minimally one word and as many additional words as fit in Width. Wrapped is a list of strings.
  664wrap_text(Width, Text, Wrapped) :-
  665    split_string(Text, " \t\n", " \t\n", Words),
  666    wrap_lines(Words, Width, Wrapped).
  667
  668wrap_lines([], _, []).
  669wrap_lines([H|T0], Width, [Line|Lines]) :-
  670    !,
  671    string_length(H, Len),
  672    take_line(T0, T1, Width, Len, LineWords),
  673    atomics_to_string([H|LineWords], " ", Line),
  674    wrap_lines(T1, Width, Lines).
  675
  676take_line([H|T0], T, Width, Here, [H|Line]) :-
  677    string_length(H, Len),
  678    NewHere is Here+Len+1,
  679    NewHere =< Width,
  680    !,
  681    take_line(T0, T, Width, NewHere, Line).
  682take_line(T, T, _, _, []).
 options(+Type, +ShortOpt, +LongOpts, +Meta)//
Emit a line with options.
  688options(Type, ShortOpt, LongOpts, Meta) -->
  689    { append(ShortOpt, LongOpts, Opts) },
  690    sequence(option(Type, Meta), [', '-[]], Opts).
  691
  692option(boolean, _, Opt) -->
  693    opt(Opt).
  694option(_, Meta, Opt) -->
  695    opt(Opt),
  696    (   { short_opt(Opt) }
  697    ->  [ ' '-[] ]
  698    ;   [ '='-[] ]
  699    ),
  700    [ ansi(var, '~w', [Meta]) ].
 options_width(+Opt, -Width) is det
Compute the width of the column we need for the options.
  706options_width(opt(_Name, boolean, Short, Long, _Help, _Meta), W) =>
  707    length(Short, SCount),
  708    length(Long, LCount),
  709    maplist(atom_length, Long, LLens),
  710    sum_list(LLens, LLen),
  711    W is ((SCount+LCount)-1)*2 +               % ', ' seps
  712         SCount*2 +
  713         LCount*2 + LLen.
  714options_width(opt(_Name, _Type, Short, Long, _Help, Meta), W) =>
  715    length(Short, SCount),
  716    length(Long, LCount),
  717    atom_length(Meta, MLen),
  718    maplist(atom_length, Long, LLens),
  719    sum_list(LLens, LLen),
  720    W is ((SCount+LCount)-1)*2 +               % ', ' seps
  721         SCount*3 + SCount*MLen +
  722         LCount*3 + LLen + LCount*MLen.
 get_option(+Module, -Opt) is multi
Get a description for a single option. Opt is a term
opt(Name, Type, ShortFlags, Longflags, Help, Meta).
  730get_option(M, opt(help, boolean, [h,?], [help],
  731                  Help, -)) :-
  732    \+ in(M:opt_type(_, help, boolean)),       % user defined help
  733    (   in(M:opt_help(help, Help))
  734    ->  true
  735    ;   Help = "Show this help message and exit"
  736    ).
  737get_option(M, opt(Name, Type, Short, Long, Help, Meta)) :-
  738    findall(Name, in(M:opt_type(_, Name, _)), Names),
  739    list_to_set(Names, UNames),
  740    member(Name, UNames),
  741    findall(Opt-Type,
  742            in(M:opt_type(Opt, Name, Type)),
  743            Pairs),
  744    option_type(Name, Pairs, TypeT),
  745    functor(TypeT, Type, _),
  746    pairs_keys(Pairs, Opts),
  747    partition(short_opt, Opts, Short, Long),
  748    (   in(M:opt_help(Name, Help))
  749    ->  true
  750    ;   Help = ''
  751    ),
  752    (   in(M:opt_meta(Name, Meta))
  753    ->  true
  754    ;   upcase_atom(Type, Meta)
  755    ).
  756
  757option_type(Name, Pairs, Type) :-
  758    pairs_values(Pairs, Types),
  759    sort(Types, [Type|UTypes]),
  760    (   UTypes = []
  761    ->  true
  762    ;   print_message(warning,
  763                      error(opt_error(multiple_types(Name, [Type|UTypes])),_))
  764    ).
 in(:Goal)
As call/1, but fails silently if there is no predicate that implements Goal.
  771in(Goal) :-
  772    pi_head(PI, Goal),
  773    current_predicate(PI),
  774    call(Goal).
  775
  776short_opt(Opt) :-
  777    atom_length(Opt, 1).
  778
  779		 /*******************************
  780		 *      OPT ERROR HANDLING	*
  781		 *******************************/
 opt_error(+Error)
Errors
- opt_error(Term)
  787opt_error(Error) :-
  788    throw(error(opt_error(Error), _)).
  789
  790:- multifile
  791    prolog:error_message//1.  792
  793prolog:error_message(opt_error(Error)) -->
  794    opt_error(Error).
  795
  796opt_error(unknown_option(M:Opt)) -->
  797    [ 'Unknown option: '-[] ],
  798    opt(Opt),
  799    hint_help(M).
  800opt_error(missing_value(Opt, Type)) -->
  801    [ 'Option '-[] ],
  802    opt(Opt),
  803    [ ' requires an argument (of type ~p)'-[Type] ].
  804opt_error(value_type(Opt, Type, Found)) -->
  805    [ 'Option '-[] ],
  806    opt(Opt), [' requires'],
  807    type(Type),
  808    [ ' (found '-[], ansi(code, '~w', [Found]), ')'-[] ].
  809opt_error(access_file(File, exist)) -->
  810    [ 'File '-[], ansi(code, '~w', [File]),
  811      ' does not exist'-[]
  812    ].
  813opt_error(access_file(File, Access)) -->
  814    { access_verb(Access, Verb) },
  815    [ 'Cannot access file '-[], ansi(code, '~w', [File]),
  816      ' for '-[], ansi(code, '~w', [Verb])
  817    ].
  818
  819access_verb(read,    reading).
  820access_verb(write,   writing).
  821access_verb(append,  writing).
  822access_verb(execute, executing).
  823
  824hint_help(M) -->
  825    { in(M:opt_type(Opt, help, boolean)) },
  826    !,
  827    [ ' (' ], opt(Opt), [' for help)'].
  828hint_help(_) -->
  829    [ ' (-h for help)'-[] ].
  830
  831opt(Opt) -->
  832    { short_opt(Opt) },
  833    !,
  834    [ ansi(bold, '-~w', [Opt]) ].
  835opt(Opt) -->
  836    [ ansi(bold, '--~w', [Opt]) ].
  837
  838type(A|B) -->
  839    type(A), [' or'],
  840    type(B).
  841type(oneof([One])) -->
  842    !,
  843    [ ' ' ],
  844    atom(One).
  845type(oneof(List)) -->
  846    !,
  847    [ ' one of '-[] ],
  848    sequence(atom, [', '], List).
  849type(between(Low, High)) -->
  850    !,
  851    [ ' a number '-[],
  852      ansi(code, '~w', [Low]), '..', ansi(code, '~w', [High])
  853    ].
  854type(nonneg) -->
  855    [ ' a non-negative integer'-[] ].
  856type(natural) -->
  857    [ ' a positive integer (>= 1)'-[] ].
  858type(file(Access)) -->
  859    [ ' a file with ~w access'-[Access] ].
  860type(Type) -->
  861    [ ' an argument of type '-[], ansi(code, '~w', [Type]) ].
  862
  863atom(A) -->
  864    [ ansi(code, '~w', [A]) ].
  865
  866
  867		 /*******************************
  868		 *         DEBUG SUPPORT	*
  869		 *******************************/
 cli_parse_debug_options(+OptionsIn, -Options) is det
Parse certain commandline options for debugging and development purposes. Options processed are below. Note that the option argument is an atom such that these options may be activated as e.g., --debug='http(_)'.
debug(Topic)
Call debug(Topic). See debug/1 and debug/3.
spy Predicate
Place a spy-point on Predicate.
gspy(Predicate)
As spy using the graphical debugger. See tspy/1.
interactive(true)
Start the Prolog toplevel after main/1 completes.
  887cli_parse_debug_options([], []).
  888cli_parse_debug_options([H|T0], Opts) :-
  889    debug_option(H),
  890    !,
  891    cli_parse_debug_options(T0, Opts).
  892cli_parse_debug_options([H|T0], [H|T]) :-
  893    cli_parse_debug_options(T0, T).
  894
  895debug_option(interactive(true)) :-
  896    asserta(interactive).
  897debug_option(debug(TopicS)) :-
  898    term_string(Topic, TopicS),
  899    debug(Topic).
  900debug_option(spy(Atom)) :-
  901    atom_pi(Atom, PI),
  902    spy(PI).
  903debug_option(gspy(Atom)) :-
  904    atom_pi(Atom, PI),
  905    tspy(PI).
  906
  907atom_pi(Atom, Module:PI) :-
  908    split(Atom, :, Module, PiAtom),
  909    !,
  910    atom_pi(PiAtom, PI).
  911atom_pi(Atom, Name//Arity) :-
  912    split(Atom, //, Name, Arity),
  913    !.
  914atom_pi(Atom, Name/Arity) :-
  915    split(Atom, /, Name, Arity),
  916    !.
  917atom_pi(Atom, _) :-
  918    format(user_error, 'Invalid predicate indicator: "~w"~n', [Atom]),
  919    halt(1).
  920
  921split(Atom, Sep, Before, After) :-
  922    sub_atom(Atom, BL, _, AL, Sep),
  923    !,
  924    sub_atom(Atom, 0, BL, _, Before),
  925    sub_atom(Atom, _, AL, 0, AfterAtom),
  926    (   atom_number(AfterAtom, After)
  927    ->  true
  928    ;   After = AfterAtom
  929    ).
 cli_enable_development_system
Re-enable the development environment. Currently re-enables xpce if this was loaded, but not initialised and causes the interactive toplevel to be re-enabled.

This predicate may be called from main/1 to enter the Prolog toplevel rather than terminating the application after main/1 completes.

  942cli_enable_development_system :-
  943    on_signal(int, _, debug),
  944    set_prolog_flag(xpce_threaded, true),
  945    set_prolog_flag(message_ide, true),
  946    (   current_prolog_flag(xpce_version, _)
  947    ->  use_module(library(pce_dispatch)),
  948        memberchk(Goal, [pce_dispatch([])]),
  949        call(Goal)
  950    ;   true
  951    ),
  952    set_prolog_flag(toplevel_goal, prolog).
  953
  954
  955		 /*******************************
  956		 *          IDE SUPPORT		*
  957		 *******************************/
  958
  959:- multifile
  960    prolog:called_by/2.  961
  962prolog:called_by(main, [main(_)]).
  963prolog:called_by(argv_options(_,_,_),
  964                 [ opt_type(_,_,_),
  965                   opt_help(_,_),
  966                   opt_meta(_,_)
  967                 ])