View source with formatted 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)  2007-2020, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    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(settings,
   38          [ setting/4,                  % :Name, +Type, +Default, +Comment
   39            setting/2,                  % :Name, ?Value
   40            set_setting/2,              % :Name, +Value
   41            set_setting_default/2,      % :Name, +Value
   42            restore_setting/1,          % :Name
   43            load_settings/1,            % +File
   44            load_settings/2,            % +File, +Options
   45            save_settings/0,
   46            save_settings/1,            % +File
   47            current_setting/1,          % Module:Name
   48            setting_property/2,         % ?Setting, ?Property
   49            list_settings/0,
   50            list_settings/1,            % +Module
   51
   52            convert_setting_text/3      % +Type, +Text, -Value
   53          ]).   54:- use_module(library(arithmetic),[arithmetic_expression_value/2]).   55
   56:- autoload(library(broadcast),[broadcast/1]).   57:- autoload(library(debug),[debug/3]).   58:- autoload(library(error),[must_be/2,existence_error/2,type_error/2]).   59:- autoload(library(option),[option/3]).   60
   61:- set_prolog_flag(generate_debug_info, false).   62
   63/** <module> Setting management
   64
   65This library allows management  of   configuration  settings  for Prolog
   66applications. Applications define settings  in   one  or  multiple files
   67using the directive setting/4 as illustrated below:
   68
   69==
   70:- use_module(library(settings)).
   71
   72:- setting(version, atom,   '1.0', 'Current version').
   73:- setting(timeout, number,    20, 'Timeout in seconds').
   74==
   75
   76The directive is subject to   term_expansion/2,  which guarantees proper
   77synchronisation of the  database  if   source-files  are  reloaded. This
   78implies it is *not* possible to call setting/4 as a predicate.
   79
   80Settings are local to a  module.  This   implies  they  are defined in a
   81two-level namespace. Managing settings  per   module  greatly simplifies
   82assembling large applications from multiple   modules that configuration
   83through  settings.  This  settings  management  library  ensures  proper
   84access, loading and saving of settings.
   85
   86@see    library(config) distributed with XPCE provides an alternative
   87        aimed at graphical applications.
   88@author Jan Wielemaker
   89*/
   90
   91:- dynamic
   92    st_value/3,                     % Name, Module, Value
   93    st_default/3,                   % Name, Module, Value
   94    local_file/1,                   % Path
   95    st_modified/0.   96
   97:- multifile
   98    current_setting/6.              % Name, Module, Type, Default, Comment, Source
   99
  100:- meta_predicate
  101    setting(:, +, +, +),
  102    setting(:, ?),
  103    set_setting(:, +),
  104    set_setting_default(:, +),
  105    current_setting(:),
  106    restore_setting(:).  107
  108:- predicate_options(load_settings/2, 2, [undefined(oneof([load,error]))]).  109
  110curr_setting(Name, Module, Type, Default, Comment, Src) :-
  111    current_setting(Name, Module, Type, Default0, Comment, Src),
  112    (   st_default(Name, Module, Default1)
  113    ->  Default = Default1
  114    ;   Default = Default0
  115    ).
  116
  117%!  setting(:Name, +Type, +Default, +Comment) is det.
  118%
  119%   Define a  setting.  Name denotes  the name of the  setting, Type
  120%   its type.  Default is the  value before it is  modified. Default
  121%   can  refer  to  environment  variables and  can  use  arithmetic
  122%   expressions as defined by eval_default/4.
  123%
  124%   If a second declaration for  a   setting  is  encountered, it is
  125%   ignored  if  Type  and  Default  are    the  same.  Otherwise  a
  126%   permission_error is raised.
  127%
  128%   @param Name     Name of the setting (an atom)
  129%   @param Type     Type for setting.  One of =any= or a type defined
  130%                   by must_be/2.
  131%   @param Default  Default value for the setting.
  132%   @param Comment  Atom containing a (short) descriptive note.
  133
  134
  135setting(Name, Type, Default, Comment) :-
  136    throw(error(context_error(nodirective,
  137                              setting(Name, Type, Default, Comment)),
  138                _)).
  139
  140:- multifile
  141    system:term_expansion/2.  142
  143system:term_expansion((:- setting(QName, Type, Default, Comment)),
  144                    Expanded) :-
  145    \+ current_prolog_flag(xref, true),
  146    prolog_load_context(module, M0),
  147    strip_module(M0:QName, Module, Name),
  148    must_be(atom, Name),
  149    to_atom(Comment, CommentAtom),
  150    eval_default(Default, Module, Type, Value),
  151    check_type(Type, Value),
  152    source_location(File, Line),
  153    (   current_setting(Name, Module, OType, ODef, _, OldLoc),
  154        (   OType \=@= Type
  155        ;    ODef \=@= Default
  156        ),
  157        OldLoc \= (File:_)
  158    ->  format(string(Message),
  159               'Already defined at: ~w', [OldLoc]),
  160        throw(error(permission_error(redefine, setting, Module:Name),
  161                    context(Message, _)))
  162    ;   Expanded = settings:current_setting(Name, Module, Type, Default,
  163                                            CommentAtom, File:Line)
  164    ).
  165
  166to_atom(Atom, Atom) :-
  167    atom(Atom),
  168    !.
  169to_atom(String, Atom) :-
  170    format(atom(Atom), '~s', String).
  171
  172%!  setting(:Name, ?Value) is nondet.
  173%
  174%   True when Name is a currently   defined setting with Value. Note
  175%   that setting(Name, Value) only enumerates   the  settings of the
  176%   current  module.  All  settings   can    be   enumerated   using
  177%   setting(Module:Name, Value). This predicate is  =det= if Name is
  178%   ground.
  179%
  180%   @error  existence_error(setting, Name)
  181
  182setting(Module:Name, Value) :-
  183    (   nonvar(Name), nonvar(Module)
  184    ->  (   st_value(Name, Module, Value0)
  185        ->  Value = Value0
  186        ;   curr_setting(Name, Module, Type, Default, _, _)
  187        ->  eval_default(Default, Module, Type, Value)
  188        ;   existence_error(setting, Module:Name)
  189        )
  190    ;   current_setting(Name, Module, _, _, _, _),
  191        setting(Module:Name, Value)
  192    ).
  193
  194
  195:- dynamic
  196    setting_cache/3.  197:- volatile
  198    setting_cache/3.  199
  200%!  clear_setting_cache is det.
  201%
  202%   Clear the cache for evaluation of default values.
  203
  204clear_setting_cache :-
  205    retractall(setting_cache(_,_,_)).
  206
  207%!  eval_default(+Default, +Module, +Type, -Value) is det.
  208%
  209%   Convert the settings default value. The notation allows for some
  210%   `function-style' notations to make the library more generic:
  211%
  212%           * env(Name)
  213%           Get value from the given environment variable. The value
  214%           is handed to convert_setting_text/3 to convert the
  215%           textual representation into a Prolog term.  Raises an
  216%           existence_error of the variable is not defined.
  217%
  218%           * env(Name, Default)
  219%           As env(Name), but uses the value Default if the variable
  220%           is not defined.
  221%
  222%           * setting(Name)
  223%           Ask the value of another setting.
  224%
  225%           * Expression
  226%           If Type is numeric, evaluate the expression.  env(Var)
  227%           evaluates to the value of an environment variable.
  228%           If Type is =atom=, concatenate A+B+....  Elements of the
  229%           expression can be env(Name).
  230
  231:- multifile
  232    eval_default/3.                 % +Default, +Type, -Value
  233
  234eval_default(Default, _, _Type, Value) :-
  235    var(Default),
  236    !,
  237    Value = Default.
  238eval_default(Default, _, Type, Value) :-
  239    eval_default(Default, Type, Val),
  240    !,
  241    Value = Val.
  242eval_default(Default, _, _, Value) :-
  243    atomic(Default),
  244    !,
  245    Value = Default.
  246eval_default(Default, _, Type, Value) :-
  247    setting_cache(Default, Type, Val),
  248    !,
  249    Value = Val.
  250eval_default(env(Name), _, Type, Value) :-
  251    !,
  252    (   getenv(Name, TextValue)
  253    ->  convert_setting_text(Type, TextValue, Val),
  254        assert(setting_cache(env(Name), Type, Val)),
  255        Value = Val
  256    ;   existence_error(environment_variable, Name)
  257    ).
  258eval_default(env(Name, Default), _, Type, Value) :-
  259    !,
  260    (   getenv(Name, TextValue)
  261    ->  convert_setting_text(Type, TextValue, Val)
  262    ;   Val = Default
  263    ),
  264    assert(setting_cache(env(Name), Type, Val)),
  265    Value = Val.
  266eval_default(setting(Name), Module, Type, Value) :-
  267    !,
  268    strip_module(Module:Name, M, N),
  269    setting(M:N, Value),
  270    must_be(Type, Value).
  271eval_default(Expr, _, Type, Value) :-
  272    numeric_type(Type, Basic),
  273    !,
  274    arithmetic_expression_value(Expr, Val0),
  275    (   Basic == float
  276    ->  Val is float(Val0)
  277    ;   Basic = integer
  278    ->  Val is round(Val0)
  279    ;   Val = Val0
  280    ),
  281    assert(setting_cache(Expr, Type, Val)),
  282    Value = Val.
  283eval_default(A+B, Module, atom, Value) :-
  284    !,
  285    phrase(expr_to_list(A+B, Module), L),
  286    atomic_list_concat(L, Val),
  287    assert(setting_cache(A+B, atom, Val)),
  288    Value = Val.
  289eval_default(List, Module, list(Type), Value) :-
  290    !,
  291    eval_list_default(List, Module, Type, Val),
  292    assert(setting_cache(List, list(Type), Val)),
  293    Value = Val.
  294eval_default(Default, _, _, Default).
  295
  296
  297%!  eval_list_default(+List, +Module, +ElementType, -DefaultList)
  298%
  299%   Evaluate the default for a list of values.
  300
  301eval_list_default([], _, _, []).
  302eval_list_default([H0|T0], Module, Type, [H|T]) :-
  303    eval_default(H0, Module, Type, H),
  304    eval_list_default(T0, Module, Type, T).
  305
  306%!  expr_to_list(+Expression, +Module)// is det.
  307%
  308%   Process the components to create an  atom. Atom concatenation is
  309%   expressed as A+B. Components may refer to envrionment variables.
  310
  311expr_to_list(A+B, Module) -->
  312    !,
  313    expr_to_list(A, Module),
  314    expr_to_list(B, Module).
  315expr_to_list(env(Name), _) -->
  316    !,
  317    (   { getenv(Name, Text) }
  318    ->  [Text]
  319    ;   { existence_error(environment_variable, Name) }
  320    ).
  321expr_to_list(env(Name, Default), _) -->
  322    !,
  323    (   { getenv(Name, Text) }
  324    ->  [Text]
  325    ;   [Default]
  326    ).
  327expr_to_list(setting(Name), Module) -->
  328    !,
  329    { strip_module(Module:Name, M, N),
  330      setting(M:N, Value)
  331    },
  332    [ Value ].
  333expr_to_list(A, _) -->
  334    [A].
  335
  336%!  env(+Name:atom, -Value:number) is det.
  337%!  env(+Name:atom, +Default:number, -Value:number) is det
  338%
  339%   Evaluate  environment  variables   on    behalf   of  arithmetic
  340%   expressions.
  341
  342:- arithmetic_function(env/1).  343:- arithmetic_function(env/2).  344
  345env(Name, Value) :-
  346    (   getenv(Name, Text)
  347    ->  convert_setting_text(number, Text, Value)
  348    ;   existence_error(environment_variable, Name)
  349    ).
  350env(Name, Default, Value) :-
  351    (   getenv(Name, Text)
  352    ->  convert_setting_text(number, Text, Value)
  353    ;   Value = Default
  354    ).
  355
  356
  357%!  numeric_type(+Type, -BaseType)
  358%
  359%   True if Type is a numeric type   and  BaseType is the associated
  360%   basic Prolog type. BaseType is  one   of  =integer=,  =float= or
  361%   =number=.
  362
  363numeric_type(integer, integer).
  364numeric_type(nonneg, integer).
  365numeric_type(float, float).
  366numeric_type(between(L,_), Type) :-
  367    ( integer(L) -> Type = integer ; Type = float ).
  368
  369
  370%!  set_setting(:Name, +Value) is det.
  371%
  372%   Change a setting. Performs existence   and type-checking for the
  373%   setting. If the effective value  of   the  setting is changed it
  374%   broadcasts the event below.
  375%
  376%	settings(changed(Module:Name, Old, New))
  377%
  378%   Note that modified settings are   __not__  automatically persistent.
  379%   The application should call save_settings/0 to persist the changes.
  380%
  381%   @error  existence_error(setting, Name)
  382%   @error  type_error(Type, Value)
  383
  384set_setting(QName, Value) :-
  385    strip_module(QName, Module, Name),
  386    must_be(atom, Name),
  387    (   curr_setting(Name, Module, Type, Default0, _Comment, _Src),
  388        eval_default(Default0, Module, Type, Default)
  389    ->  setting(Module:Name, Old),
  390        (   Value == Default
  391        ->  retract_setting(Module:Name)
  392        ;   st_value(Name, Module, Value)
  393        ->  true
  394        ;   check_type(Type, Value)
  395        ->  retract_setting(Module:Name),
  396            assert_setting(Module:Name, Value)
  397        ),
  398        (   Old == Value
  399        ->  true
  400        ;   broadcast(settings(changed(Module:Name, Old, Value))),
  401            clear_setting_cache     % might influence dependent settings
  402        )
  403    ;   existence_error(setting, Name)
  404    ).
  405
  406retract_setting(Module:Name) :-
  407    set_settings_modified,
  408    retractall(st_value(Name, Module, _)).
  409
  410assert_setting(Module:Name, Value) :-
  411    set_settings_modified,
  412    assert(st_value(Name, Module, Value)).
  413
  414set_settings_modified :-
  415    st_modified, !.
  416set_settings_modified :-
  417    assertz(st_modified).
  418
  419
  420%!  restore_setting(:Name) is det.
  421%
  422%   Restore the value of setting Name   to  its default. Broadcast a
  423%   change like set_setting/2 if  the  current   value  is  not  the
  424%   default.
  425
  426restore_setting(QName) :-
  427    strip_module(QName, Module, Name),
  428    must_be(atom, Name),
  429    (   st_value(Name, Module, Old)
  430    ->  retract_setting(Module:Name),
  431        setting(Module:Name, Value),
  432        (   Old \== Value
  433        ->  broadcast(settings(changed(Module:Name, Old, Value)))
  434        ;   true
  435        )
  436    ;   true
  437    ).
  438
  439%!  set_setting_default(:Name, +Default) is det.
  440%
  441%   Change the default for a setting.  The   effect  is  the same as
  442%   set_setting/2, but the new value is  considered the default when
  443%   saving and restoring  a  setting.  It   is  intended  to  change
  444%   application defaults in a particular context.
  445
  446set_setting_default(QName, Default) :-
  447    strip_module(QName, Module, Name),
  448    must_be(atom, Name),
  449    (   current_setting(Name, Module, Type, Default0, _Comment, _Src)
  450    ->  retractall(settings:st_default(Name, Module, _)),
  451        retract_setting(Module:Name),
  452        (   Default == Default0
  453        ->  true
  454        ;   assert(settings:st_default(Name, Module, Default))
  455        ),
  456        eval_default(Default, Module, Type, Value),
  457        set_setting(Module:Name, Value)
  458    ;   existence_error(setting, Module:Name)
  459    ).
  460
  461
  462                 /*******************************
  463                 *             TYPES            *
  464                 *******************************/
  465
  466%!  check_type(+Type, +Term)
  467%
  468%   Type  checking  for  settings.  Currently  simply  forwarded  to
  469%   must_be/2.
  470
  471check_type(Type, Term) :-
  472    must_be(Type, Term).
  473
  474
  475                 /*******************************
  476                 *             FILE             *
  477                 *******************************/
  478
  479%!  load_settings(File) is det.
  480%!  load_settings(File, +Options) is det.
  481%
  482%   Load local settings from File.  Succeeds   if  File  does not exist,
  483%   setting the default save-file to File. Options are:
  484%
  485%     * undefined(+Action)
  486%     Define how to handle settings that are not defined.  When
  487%     `error`, an error is printed and the setting is ignored.
  488%     when `load`, the setting is loaded anyway, waiting for a
  489%     definition.
  490%
  491%   If possibly changed settings need to  be persistent, the application
  492%   must call save_settings/0 as part of   its shutdown. In simple cases
  493%   calling at_halt(save_settings) is sufficient.
  494
  495load_settings(File) :-
  496    load_settings(File, []).
  497
  498load_settings(File, Options) :-
  499    absolute_file_name(File, Path,
  500                       [ access(read),
  501                         file_errors(fail)
  502                       ]),
  503    !,
  504    assert(local_file(Path)),
  505    open(Path, read, In, [encoding(utf8)]),
  506    read_setting(In, T0),
  507    call_cleanup(load_settings(T0, In, Options), close(In)),
  508    clear_setting_cache.
  509load_settings(File, _) :-
  510    absolute_file_name(File, Path,
  511                       [ access(write),
  512                         file_errors(fail)
  513                       ]),
  514    !,
  515    assert(local_file(Path)).
  516load_settings(_, _).
  517
  518load_settings(end_of_file, _, _) :- !.
  519load_settings(Setting, In, Options) :-
  520    catch(store_setting(Setting, Options), E,
  521          print_message(warning, E)),
  522    read_setting(In, Next),
  523    load_settings(Next, In, Options).
  524
  525read_setting(In, Term) :-
  526    read_term(In, Term,
  527              [ syntax_errors(dec10)
  528              ]).
  529
  530%!  store_setting(Term, +Options)
  531%
  532%   Store setting loaded from file in the Prolog database.
  533
  534store_setting(setting(Module:Name, Value), _) :-
  535    curr_setting(Name, Module, Type, Default0, _Commentm, _Src),
  536    !,
  537    eval_default(Default0, Module, Type, Default),
  538    (   Value == Default
  539    ->  true
  540    ;   check_type(Type, Value)
  541    ->  retractall(st_value(Name, Module, _)),
  542        assert(st_value(Name, Module, Value)),
  543        broadcast(settings(changed(Module:Name, Default, Value)))
  544    ).
  545store_setting(setting(Module:Name, Value), Options) :-
  546    !,
  547    (   option(undefined(load), Options, load)
  548    ->  retractall(st_value(Name, Module, _)),
  549        assert(st_value(Name, Module, Value))
  550    ;   existence_error(setting, Module:Name)
  551    ).
  552store_setting(Term, _) :-
  553    type_error(setting, Term).
  554
  555%!  save_settings is semidet.
  556%!  save_settings(+File) is semidet.
  557%
  558%   Save modified settings to File. Fails  silently if the settings file
  559%   cannot be written. The save_settings/0  only   attempts  to save the
  560%   settings file if some setting was modified using set_setting/2.
  561%
  562%   @error context_error(settings, no_default_file)  for save_settings/0
  563%   if no default location is known.
  564
  565save_settings :-
  566    st_modified,
  567    !,
  568    (   local_file(File)
  569    ->  save_settings(File)
  570    ;   throw(error(context_error(settings, no_default_file), _))
  571    ).
  572save_settings.
  573
  574save_settings(File) :-
  575    absolute_file_name(File, Path,
  576                       [ access(write)
  577                       ]),
  578    setup_call_cleanup(
  579        open(Path, write, Out,
  580             [ encoding(utf8),
  581               bom(true)
  582             ]),
  583        ( write_setting_header(Out),
  584          forall(current_setting(Name, Module, _, _, _, _),
  585                 save_setting(Out, Module:Name))
  586        ),
  587        close(Out)).
  588
  589write_setting_header(Out) :-
  590    get_time(Now),
  591    format_time(string(Date), '%+', Now),
  592    format(Out, '/*  Saved settings~n', []),
  593    format(Out, '    Date: ~w~n', [Date]),
  594    format(Out, '*/~n~n', []).
  595
  596save_setting(Out, Module:Name) :-
  597    curr_setting(Name, Module, Type, Default, Comment, _Src),
  598    (   st_value(Name, Module, Value),
  599        \+ ( eval_default(Default, Module, Type, DefValue),
  600             debug(setting, '~w <-> ~w~n', [DefValue, Value]),
  601             DefValue =@= Value
  602           )
  603    ->  format(Out, '~n%\t~w~n', [Comment]),
  604        format(Out, 'setting(~q:~q, ~q).~n', [Module, Name, Value])
  605    ;   true
  606    ).
  607
  608%!  current_setting(?Setting) is nondet.
  609%
  610%   True if Setting is a currently defined setting
  611
  612current_setting(Setting) :-
  613    ground(Setting),
  614    !,
  615    strip_module(Setting, Module, Name),
  616    current_setting(Name, Module, _, _, _, _).
  617current_setting(Module:Name) :-
  618    current_setting(Name, Module, _, _, _, _).
  619
  620%!  setting_property(+Setting, +Property) is det.
  621%!  setting_property(?Setting, ?Property) is nondet.
  622%
  623%   Query currently defined settings.  Property is one of
  624%
  625%           * comment(-Atom)
  626%           * type(-Type)
  627%           Type of the setting.
  628%           * default(-Default)
  629%           Default value.  If this is an expression, it is
  630%           evaluated.
  631%           * source(-File:-Line)
  632%           Location where the setting is defined.
  633
  634setting_property(Setting, Property) :-
  635    ground(Setting),
  636    !,
  637    Setting = Module:Name,
  638    curr_setting(Name, Module, Type, Default, Comment, Src),
  639    !,
  640    setting_property(Property, Module, Type, Default, Comment, Src).
  641setting_property(Setting, Property) :-
  642    Setting = Module:Name,
  643    curr_setting(Name, Module, Type, Default, Comment, Src),
  644    setting_property(Property, Module, Type, Default, Comment, Src).
  645
  646setting_property(type(Type), _, Type, _, _, _).
  647setting_property(default(Default), M, Type, Default0, _, _) :-
  648    eval_default(Default0, M, Type, Default).
  649setting_property(comment(Comment), _, _, _, Comment, _).
  650setting_property(source(Src), _, _, _, _, Src).
  651
  652%!  list_settings is det.
  653%!  list_settings(+Module) is det.
  654%
  655%   List settings to =current_output=. The   second  form only lists
  656%   settings on the matching module.
  657%
  658%   @tbd    Compute the required column widths
  659
  660list_settings :-
  661    list_settings(_).
  662
  663list_settings(Spec) :-
  664    spec_term(Spec, Term),
  665    TS1 = 25,
  666    TS2 = 40,
  667    format('~`=t~72|~n'),
  668    format('~w~t~*| ~w~w~t~*| ~w~n',
  669           ['Name', TS1, 'Value (*=modified)', '', TS2, 'Comment']),
  670    format('~`=t~72|~n'),
  671    forall(current_setting(Term),
  672           list_setting(Term, TS1, TS2)).
  673
  674spec_term(M:S, M:S) :- !.
  675spec_term(M, M:_).
  676
  677
  678list_setting(Module:Name, TS1, TS2) :-
  679    curr_setting(Name, Module, Type, Default0, Comment, _Src),
  680    eval_default(Default0, Module, Type, Default),
  681    setting(Module:Name, Value),
  682    (   Value \== Default
  683    ->  Modified = (*)
  684    ;   Modified = ''
  685    ),
  686    format('~w~t~*| ~q~w~t~*| ~w~n',
  687           [Module:Name, TS1, Value, Modified, TS2, Comment]).
  688
  689
  690                 /*******************************
  691                 *            TYPES             *
  692                 *******************************/
  693
  694%!  convert_setting_text(+Type, +Text, -Value)
  695%
  696%   Converts from textual form to  Prolog   Value.  Used  to convert
  697%   values obtained from the environment.  Public to provide support
  698%   in user-interfaces to this library.
  699%
  700%   @error  type_error(Type, Value)
  701
  702:- multifile
  703    convert_text/3.                 % +Type, +Text, -Value
  704
  705convert_setting_text(Type, Text, Value) :-
  706    convert_text(Type, Text, Value),
  707    !.
  708convert_setting_text(atom, Value, Value) :-
  709    !,
  710    must_be(atom, Value).
  711convert_setting_text(boolean, Value, Value) :-
  712    !,
  713    must_be(boolean, Value).
  714convert_setting_text(integer, Atom, Number) :-
  715    !,
  716    term_to_atom(Term, Atom),
  717    Number is round(Term).
  718convert_setting_text(float, Atom, Number) :-
  719    !,
  720    term_to_atom(Term, Atom),
  721    Number is float(Term).
  722convert_setting_text(between(L,U), Atom, Number) :-
  723    !,
  724    (   integer(L)
  725    ->  convert_setting_text(integer, Atom, Number)
  726    ;   convert_setting_text(float, Atom, Number)
  727    ),
  728    must_be(between(L,U), Number).
  729convert_setting_text(Type, Atom, Term) :-
  730    term_to_atom(Term, Atom),
  731    must_be(Type, Term).
  732
  733
  734                 /*******************************
  735                 *            SANDBOX           *
  736                 *******************************/
  737
  738:- multifile
  739    sandbox:safe_meta_predicate/1.  740
  741sandbox:safe_meta_predicate(settings:setting/2).
  742
  743
  744		 /*******************************
  745		 *           MESSAGES		*
  746		 *******************************/
  747
  748:- multifile
  749    prolog:error_message//1.  750
  751prolog:error_message(context_error(settings, no_default_file)) -->
  752    [ 'save_settings/0: no default file' ]