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),[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).

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.
   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    ).
 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.
  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).
 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)
  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.
 clear_setting_cache is det
Clear the cache for evaluation of default values.
  204clear_setting_cache :-
  205    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).
  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).
 eval_list_default(+List, +Module, +ElementType, -DefaultList)
Evaluate the default for a list of values.
  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).
 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.
  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].
 env(+Name:atom, -Value:number) is det
 env(+Name:atom, +Default:number, -Value:number) is det
Evaluate environment variables on behalf of arithmetic expressions.
  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    ).
 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.
  363numeric_type(integer, integer).
  364numeric_type(nonneg, integer).
  365numeric_type(float, float).
  366numeric_type(between(L,_), Type) :-
  367    ( 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)
  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).
 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.
  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    ).
 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.
  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                 *******************************/
 check_type(+Type, +Term)
Type checking for settings. Currently simply forwarded to must_be/2.
  471check_type(Type, Term) :-
  472    must_be(Type, Term).
  473
  474
  475                 /*******************************
  476                 *             FILE             *
  477                 *******************************/
 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.

  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              ]).
 store_setting(Term, +Options)
Store setting loaded from file in the Prolog database.
  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).
 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.
  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    ).
 current_setting(?Setting) is nondet
True if Setting is a currently defined setting
  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, _, _, _, _).
 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.
  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).
 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
  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                 *******************************/
 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)
  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' ]