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)  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),
   55              [ arithmetic_function/1,
   56                arithmetic_expression_value/2
   57              ]).   58
   59:- autoload(library(broadcast),[broadcast/1]).   60:- use_module(library(debug),[debug/3]).   61:- autoload(library(error),[must_be/2,existence_error/2,type_error/2]).   62:- autoload(library(option),[option/3]).   63
   64:- set_prolog_flag(generate_debug_info, false).

Setting management

This library allows management of configuration settings for Prolog applications. Applications define settings in one or multiple files using the directive setting/4 as illustrated below:

:- use_module(library(settings)).

:- setting(version, atom,   '1.0', 'Current version').
:- setting(timeout, number,    20, 'Timeout in seconds').

The directive is subject to term_expansion/2, which guarantees proper synchronisation of the database if source-files are reloaded. This implies it is not possible to call setting/4 as a predicate.

Settings are local to a module. This implies they are defined in a two-level namespace. Managing settings per module greatly simplifies assembling large applications from multiple modules that configuration through settings. This settings management library ensures proper access, loading and saving of settings.

author
- Jan Wielemaker */
See also
- library(config) distributed with XPCE provides an alternative aimed at graphical applications.
   94:- dynamic
   95    st_value/3,                     % Name, Module, Value
   96    st_default/3,                   % Name, Module, Value
   97    local_file/1,                   % Path
   98    st_modified/0.   99
  100:- multifile
  101    current_setting/6.              % Name, Module, Type, Default, Comment, Source
  102
  103:- meta_predicate
  104    setting(:, +, +, +),
  105    setting(:, ?),
  106    set_setting(:, +),
  107    set_setting_default(:, +),
  108    current_setting(:),
  109    restore_setting(:).  110
  111:- predicate_options(load_settings/2, 2, [undefined(oneof([load,error]))]).  112
  113curr_setting(Name, Module, Type, Default, Comment, Src) :-
  114    current_setting(Name, Module, Type, Default0, Comment, Src),
  115    (   st_default(Name, Module, Default1)
  116    ->  Default = Default1
  117    ;   Default = Default0
  118    ).
 setting(:Name, +Type, +Default, +Comment) is det
Define a setting. Name denotes the name of the setting, Type its type. Default is the value before it is modified. Default can refer to environment variables and can use arithmetic expressions as defined by eval_default/4.

If a second declaration for a setting is encountered, it is ignored if Type and Default are the same. Otherwise a permission_error is raised.

Arguments:
Name- Name of the setting (an atom)
Type- Type for setting. One of any or a type defined by must_be/2.
Default- Default value for the setting.
Comment- Atom containing a (short) descriptive note.
  138setting(Name, Type, Default, Comment) :-
  139    throw(error(context_error(nodirective,
  140                              setting(Name, Type, Default, Comment)),
  141                _)).
  142
  143:- multifile
  144    system:term_expansion/2.  145
  146system:term_expansion((:- setting(QName, Type, Default, Comment)),
  147                    Expanded) :-
  148    \+ current_prolog_flag(xref, true),
  149    prolog_load_context(module, M0),
  150    strip_module(M0:QName, Module, Name),
  151    must_be(atom, Name),
  152    to_atom(Comment, CommentAtom),
  153    eval_default(Default, Module, Type, Value),
  154    check_type(Type, Value),
  155    source_location(File, Line),
  156    (   current_setting(Name, Module, OType, ODef, _, OldLoc),
  157        (   OType \=@= Type
  158        ;    ODef \=@= Default
  159        ),
  160        OldLoc \= (File:_)
  161    ->  format(string(Message),
  162               'Already defined at: ~w', [OldLoc]),
  163        throw(error(permission_error(redefine, setting, Module:Name),
  164                    context(Message, _)))
  165    ;   Expanded = settings:current_setting(Name, Module, Type, Default,
  166                                            CommentAtom, File:Line)
  167    ).
  168
  169to_atom(Atom, Atom) :-
  170    atom(Atom),
  171    !.
  172to_atom(String, Atom) :-
  173    format(atom(Atom), '~s', String).
 setting(:Name, ?Value) is nondet
True when Name is a currently defined setting with Value. Note that setting(Name, Value) only enumerates the settings of the current module. All settings can be enumerated using setting(Module:Name, Value). This predicate is det if Name is ground.
Errors
- existence_error(setting, Name)
  185setting(Module:Name, Value) :-
  186    (   nonvar(Name), nonvar(Module)
  187    ->  (   st_value(Name, Module, Value0)
  188        ->  Value = Value0
  189        ;   curr_setting(Name, Module, Type, Default, _, _)
  190        ->  eval_default(Default, Module, Type, Value)
  191        ;   existence_error(setting, Module:Name)
  192        )
  193    ;   current_setting(Name, Module, _, _, _, _),
  194        setting(Module:Name, Value)
  195    ).
  196
  197
  198:- dynamic
  199    setting_cache/3.  200:- volatile
  201    setting_cache/3.
 clear_setting_cache is det
Clear the cache for evaluation of default values.
  207clear_setting_cache :-
  208    retractall(setting_cache(_,_,_)).
 eval_default(+Default, +Module, +Type, -Value) is det
Convert the settings default value. The notation allows for some `function-style' notations to make the library more generic:
env(Name)
Get value from the given environment variable. The value is handed to convert_setting_text/3 to convert the textual representation into a Prolog term. Raises an existence_error of the variable is not defined.
env(Name, Default)
As env(Name), but uses the value Default if the variable is not defined.
setting(Name)
Ask the value of another setting.
Expression
If Type is numeric, evaluate the expression. env(Var) evaluates to the value of an environment variable. If Type is atom, concatenate A+B+.... Elements of the expression can be env(Name).
  234:- multifile
  235    eval_default/3.                 % +Default, +Type, -Value
  236
  237eval_default(Default, _, _Type, Value) :-
  238    var(Default),
  239    !,
  240    Value = Default.
  241eval_default(Default, _, Type, Value) :-
  242    eval_default(Default, Type, Val),
  243    !,
  244    Value = Val.
  245eval_default(Default, _, _, Value) :-
  246    atomic(Default),
  247    !,
  248    Value = Default.
  249eval_default(Default, _, Type, Value) :-
  250    setting_cache(Default, Type, Val),
  251    !,
  252    Value = Val.
  253eval_default(env(Name), _, Type, Value) :-
  254    !,
  255    (   getenv(Name, TextValue)
  256    ->  convert_setting_text(Type, TextValue, Val),
  257        assert(setting_cache(env(Name), Type, Val)),
  258        Value = Val
  259    ;   existence_error(environment_variable, Name)
  260    ).
  261eval_default(env(Name, Default), _, Type, Value) :-
  262    !,
  263    (   getenv(Name, TextValue)
  264    ->  convert_setting_text(Type, TextValue, Val)
  265    ;   Val = Default
  266    ),
  267    assert(setting_cache(env(Name), Type, Val)),
  268    Value = Val.
  269eval_default(setting(Name), Module, Type, Value) :-
  270    !,
  271    strip_module(Module:Name, M, N),
  272    setting(M:N, Value),
  273    must_be(Type, Value).
  274eval_default(Expr, _, Type, Value) :-
  275    numeric_type(Type, Basic),
  276    !,
  277    arithmetic_expression_value(Expr, Val0),
  278    (   Basic == float
  279    ->  Val is float(Val0)
  280    ;   Basic = integer
  281    ->  Val is round(Val0)
  282    ;   Val = Val0
  283    ),
  284    assert(setting_cache(Expr, Type, Val)),
  285    Value = Val.
  286eval_default(A+B, Module, atom, Value) :-
  287    !,
  288    phrase(expr_to_list(A+B, Module), L),
  289    atomic_list_concat(L, Val),
  290    assert(setting_cache(A+B, atom, Val)),
  291    Value = Val.
  292eval_default(List, Module, list(Type), Value) :-
  293    !,
  294    eval_list_default(List, Module, Type, Val),
  295    assert(setting_cache(List, list(Type), Val)),
  296    Value = Val.
  297eval_default(Default, _, _, Default).
 eval_list_default(+List, +Module, +ElementType, -DefaultList)
Evaluate the default for a list of values.
  304eval_list_default([], _, _, []).
  305eval_list_default([H0|T0], Module, Type, [H|T]) :-
  306    eval_default(H0, Module, Type, H),
  307    eval_list_default(T0, Module, Type, T).
 expr_to_list(+Expression, +Module)// is det
Process the components to create an atom. Atom concatenation is expressed as A+B. Components may refer to envrionment variables.
  314expr_to_list(A+B, Module) -->
  315    !,
  316    expr_to_list(A, Module),
  317    expr_to_list(B, Module).
  318expr_to_list(env(Name), _) -->
  319    !,
  320    (   { getenv(Name, Text) }
  321    ->  [Text]
  322    ;   { existence_error(environment_variable, Name) }
  323    ).
  324expr_to_list(env(Name, Default), _) -->
  325    !,
  326    (   { getenv(Name, Text) }
  327    ->  [Text]
  328    ;   [Default]
  329    ).
  330expr_to_list(setting(Name), Module) -->
  331    !,
  332    { strip_module(Module:Name, M, N),
  333      setting(M:N, Value)
  334    },
  335    [ Value ].
  336expr_to_list(A, _) -->
  337    [A].
 env(+Name:atom, -Value:number) is det
 env(+Name:atom, +Default:number, -Value:number) is det
Evaluate environment variables on behalf of arithmetic expressions.
  345:- arithmetic_function(env/1).  346:- arithmetic_function(env/2).  347
  348env(Name, Value) :-
  349    (   getenv(Name, Text)
  350    ->  convert_setting_text(number, Text, Value)
  351    ;   existence_error(environment_variable, Name)
  352    ).
  353env(Name, Default, Value) :-
  354    (   getenv(Name, Text)
  355    ->  convert_setting_text(number, Text, Value)
  356    ;   Value = Default
  357    ).
 numeric_type(+Type, -BaseType)
True if Type is a numeric type and BaseType is the associated basic Prolog type. BaseType is one of integer, float or number.
  366numeric_type(integer, integer).
  367numeric_type(nonneg, integer).
  368numeric_type(float, float).
  369numeric_type(between(L,_), Type) :-
  370    ( integer(L) -> Type = integer ; Type = float ).
 set_setting(:Name, +Value) is det
Change a setting. Performs existence and type-checking for the setting. If the effective value of the setting is changed it broadcasts the event below.
settings(changed(Module:Name, Old, New))

Note that modified settings are not automatically persistent. The application should call save_settings/0 to persist the changes.

Errors
- existence_error(setting, Name)
- type_error(Type, Value)
  387set_setting(QName, Value) :-
  388    strip_module(QName, Module, Name),
  389    must_be(atom, Name),
  390    (   curr_setting(Name, Module, Type, Default0, _Comment, _Src),
  391        eval_default(Default0, Module, Type, Default)
  392    ->  setting(Module:Name, Old),
  393        (   Value == Default
  394        ->  retract_setting(Module:Name)
  395        ;   st_value(Name, Module, Value)
  396        ->  true
  397        ;   check_type(Type, Value)
  398        ->  retract_setting(Module:Name),
  399            assert_setting(Module:Name, Value)
  400        ),
  401        (   Old == Value
  402        ->  true
  403        ;   broadcast(settings(changed(Module:Name, Old, Value))),
  404            clear_setting_cache     % might influence dependent settings
  405        )
  406    ;   existence_error(setting, Name)
  407    ).
  408
  409retract_setting(Module:Name) :-
  410    set_settings_modified,
  411    retractall(st_value(Name, Module, _)).
  412
  413assert_setting(Module:Name, Value) :-
  414    set_settings_modified,
  415    assert(st_value(Name, Module, Value)).
  416
  417set_settings_modified :-
  418    st_modified, !.
  419set_settings_modified :-
  420    assertz(st_modified).
 restore_setting(:Name) is det
Restore the value of setting Name to its default. Broadcast a change like set_setting/2 if the current value is not the default.
  429restore_setting(QName) :-
  430    strip_module(QName, Module, Name),
  431    must_be(atom, Name),
  432    (   st_value(Name, Module, Old)
  433    ->  retract_setting(Module:Name),
  434        setting(Module:Name, Value),
  435        (   Old \== Value
  436        ->  broadcast(settings(changed(Module:Name, Old, Value)))
  437        ;   true
  438        )
  439    ;   true
  440    ).
 set_setting_default(:Name, +Default) is det
Change the default for a setting. The effect is the same as set_setting/2, but the new value is considered the default when saving and restoring a setting. It is intended to change application defaults in a particular context.
  449set_setting_default(QName, Default) :-
  450    strip_module(QName, Module, Name),
  451    must_be(atom, Name),
  452    (   current_setting(Name, Module, Type, Default0, _Comment, _Src)
  453    ->  retractall(settings:st_default(Name, Module, _)),
  454        retract_setting(Module:Name),
  455        (   Default == Default0
  456        ->  true
  457        ;   assert(settings:st_default(Name, Module, Default))
  458        ),
  459        eval_default(Default, Module, Type, Value),
  460        set_setting(Module:Name, Value)
  461    ;   existence_error(setting, Module:Name)
  462    ).
  463
  464
  465                 /*******************************
  466                 *             TYPES            *
  467                 *******************************/
 check_type(+Type, +Term)
Type checking for settings. Currently simply forwarded to must_be/2.
  474check_type(Type, Term) :-
  475    must_be(Type, Term).
  476
  477
  478                 /*******************************
  479                 *             FILE             *
  480                 *******************************/
 load_settings(File) is det
 load_settings(File, +Options) is det
Load local settings from File. Succeeds if File does not exist, setting the default save-file to File. Options are:
undefined(+Action)
Define how to handle settings that are not defined. When error, an error is printed and the setting is ignored. when load, the setting is loaded anyway, waiting for a definition.

If possibly changed settings need to be persistent, the application must call save_settings/0 as part of its shutdown. In simple cases calling at_halt(save_settings) is sufficient.

  498load_settings(File) :-
  499    load_settings(File, []).
  500
  501load_settings(File, Options) :-
  502    absolute_file_name(File, Path,
  503                       [ access(read),
  504                         file_errors(fail)
  505                       ]),
  506    !,
  507    assert(local_file(Path)),
  508    open(Path, read, In, [encoding(utf8)]),
  509    read_setting(In, T0),
  510    call_cleanup(load_settings(T0, In, Options), close(In)),
  511    clear_setting_cache.
  512load_settings(File, _) :-
  513    absolute_file_name(File, Path,
  514                       [ access(write),
  515                         file_errors(fail)
  516                       ]),
  517    !,
  518    assert(local_file(Path)).
  519load_settings(_, _).
  520
  521load_settings(end_of_file, _, _) :- !.
  522load_settings(Setting, In, Options) :-
  523    catch(store_setting(Setting, Options), E,
  524          print_message(warning, E)),
  525    read_setting(In, Next),
  526    load_settings(Next, In, Options).
  527
  528read_setting(In, Term) :-
  529    read_term(In, Term,
  530              [ syntax_errors(dec10)
  531              ]).
 store_setting(Term, +Options)
Store setting loaded from file in the Prolog database.
  537store_setting(setting(Module:Name, Value), _) :-
  538    curr_setting(Name, Module, Type, Default0, _Commentm, _Src),
  539    !,
  540    eval_default(Default0, Module, Type, Default),
  541    (   Value == Default
  542    ->  true
  543    ;   check_type(Type, Value)
  544    ->  retractall(st_value(Name, Module, _)),
  545        assert(st_value(Name, Module, Value)),
  546        broadcast(settings(changed(Module:Name, Default, Value)))
  547    ).
  548store_setting(setting(Module:Name, Value), Options) :-
  549    !,
  550    (   option(undefined(load), Options, load)
  551    ->  retractall(st_value(Name, Module, _)),
  552        assert(st_value(Name, Module, Value))
  553    ;   existence_error(setting, Module:Name)
  554    ).
  555store_setting(Term, _) :-
  556    type_error(setting, Term).
 save_settings is semidet
 save_settings(+File) is semidet
Save modified settings to File. Fails silently if the settings file cannot be written. The save_settings/0 only attempts to save the settings file if some setting was modified using set_setting/2.
Errors
- context_error(settings, no_default_file) for save_settings/0 if no default location is known.
  568save_settings :-
  569    st_modified,
  570    !,
  571    (   local_file(File)
  572    ->  save_settings(File)
  573    ;   throw(error(context_error(settings, no_default_file), _))
  574    ).
  575save_settings.
  576
  577save_settings(File) :-
  578    absolute_file_name(File, Path,
  579                       [ access(write)
  580                       ]),
  581    setup_call_cleanup(
  582        open(Path, write, Out,
  583             [ encoding(utf8),
  584               bom(true)
  585             ]),
  586        ( write_setting_header(Out),
  587          forall(current_setting(Name, Module, _, _, _, _),
  588                 save_setting(Out, Module:Name))
  589        ),
  590        close(Out)).
  591
  592write_setting_header(Out) :-
  593    get_time(Now),
  594    format_time(string(Date), '%+', Now),
  595    format(Out, '/*  Saved settings~n', []),
  596    format(Out, '    Date: ~w~n', [Date]),
  597    format(Out, '*/~n~n', []).
  598
  599save_setting(Out, Module:Name) :-
  600    curr_setting(Name, Module, Type, Default, Comment, _Src),
  601    (   st_value(Name, Module, Value),
  602        \+ ( eval_default(Default, Module, Type, DefValue),
  603             debug(setting, '~w <-> ~w~n', [DefValue, Value]),
  604             DefValue =@= Value
  605           )
  606    ->  format(Out, '~n%\t~w~n', [Comment]),
  607        format(Out, 'setting(~q:~q, ~q).~n', [Module, Name, Value])
  608    ;   true
  609    ).
 current_setting(?Setting) is nondet
True if Setting is a currently defined setting
  615current_setting(Setting) :-
  616    ground(Setting),
  617    !,
  618    strip_module(Setting, Module, Name),
  619    current_setting(Name, Module, _, _, _, _).
  620current_setting(Module:Name) :-
  621    current_setting(Name, Module, _, _, _, _).
 setting_property(+Setting, +Property) is det
setting_property(?Setting, ?Property) is nondet
Query currently defined settings. Property is one of
comment(-Atom)
type(-Type)
Type of the setting.
default(-Default)
Default value. If this is an expression, it is evaluated.
source((-File:-Line))
Location where the setting is defined.
  637setting_property(Setting, Property) :-
  638    ground(Setting),
  639    !,
  640    Setting = Module:Name,
  641    curr_setting(Name, Module, Type, Default, Comment, Src),
  642    !,
  643    setting_property(Property, Module, Type, Default, Comment, Src).
  644setting_property(Setting, Property) :-
  645    Setting = Module:Name,
  646    curr_setting(Name, Module, Type, Default, Comment, Src),
  647    setting_property(Property, Module, Type, Default, Comment, Src).
  648
  649setting_property(type(Type), _, Type, _, _, _).
  650setting_property(default(Default), M, Type, Default0, _, _) :-
  651    eval_default(Default0, M, Type, Default).
  652setting_property(comment(Comment), _, _, _, Comment, _).
  653setting_property(source(Src), _, _, _, _, Src).
 list_settings is det
 list_settings(+Module) is det
List settings to current_output. The second form only lists settings on the matching module.
To be done
- Compute the required column widths
  663list_settings :-
  664    list_settings(_).
  665
  666list_settings(Spec) :-
  667    spec_term(Spec, Term),
  668    TS1 = 25,
  669    TS2 = 40,
  670    format('~`=t~72|~n'),
  671    format('~w~t~*| ~w~w~t~*| ~w~n',
  672           ['Name', TS1, 'Value (*=modified)', '', TS2, 'Comment']),
  673    format('~`=t~72|~n'),
  674    forall(current_setting(Term),
  675           list_setting(Term, TS1, TS2)).
  676
  677spec_term(M:S, M:S) :- !.
  678spec_term(M, M:_).
  679
  680
  681list_setting(Module:Name, TS1, TS2) :-
  682    curr_setting(Name, Module, Type, Default0, Comment, _Src),
  683    eval_default(Default0, Module, Type, Default),
  684    setting(Module:Name, Value),
  685    (   Value \== Default
  686    ->  Modified = (*)
  687    ;   Modified = ''
  688    ),
  689    format('~w~t~*| ~q~w~t~*| ~w~n',
  690           [Module:Name, TS1, Value, Modified, TS2, Comment]).
  691
  692
  693                 /*******************************
  694                 *            TYPES             *
  695                 *******************************/
 convert_setting_text(+Type, +Text, -Value)
Converts from textual form to Prolog Value. Used to convert values obtained from the environment. Public to provide support in user-interfaces to this library.
Errors
- type_error(Type, Value)
  705:- multifile
  706    convert_text/3.                 % +Type, +Text, -Value
  707
  708convert_setting_text(Type, Text, Value) :-
  709    convert_text(Type, Text, Value),
  710    !.
  711convert_setting_text(atom, Value, Value) :-
  712    !,
  713    must_be(atom, Value).
  714convert_setting_text(boolean, Value, Value) :-
  715    !,
  716    must_be(boolean, Value).
  717convert_setting_text(integer, Atom, Number) :-
  718    !,
  719    term_to_atom(Term, Atom),
  720    Number is round(Term).
  721convert_setting_text(float, Atom, Number) :-
  722    !,
  723    term_to_atom(Term, Atom),
  724    Number is float(Term).
  725convert_setting_text(between(L,U), Atom, Number) :-
  726    !,
  727    (   integer(L)
  728    ->  convert_setting_text(integer, Atom, Number)
  729    ;   convert_setting_text(float, Atom, Number)
  730    ),
  731    must_be(between(L,U), Number).
  732convert_setting_text(Type, Atom, Term) :-
  733    term_to_atom(Term, Atom),
  734    must_be(Type, Term).
  735
  736
  737                 /*******************************
  738                 *            SANDBOX           *
  739                 *******************************/
  740
  741:- multifile
  742    sandbox:safe_meta_predicate/1.  743
  744sandbox:safe_meta_predicate(settings:setting/2).
  745
  746
  747		 /*******************************
  748		 *           MESSAGES		*
  749		 *******************************/
  750
  751:- multifile
  752    prolog:error_message//1.  753
  754prolog:error_message(context_error(settings, no_default_file)) -->
  755    [ 'save_settings/0: no default file' ]