function varargout = cosmo_warning(message, varargin)
% show a warning message; by default just once for each message
%
% cosmo_warning(message, ...)
% cosmo_warning(state)
% state=cosmo_warning()
%
% Inputs:
% message warning message to be shown, or one of:
% 'on' : show all warning messages
% 'off' : show no warning messages
% 'once' : show each warning message once [default]
% 'reset':
% ... if a warning message is provided according with
% placeholders as used in sprintf, then the subsequent
% arguments should contain their values
% state if a struct, then this queries or sets the state of
% cosmo_warning.
%
% Notes:
% - this function works more or less like matlab's warning function,
% except that by default each warning is just shown once.
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
if isempty(get_from_state('when'))
set_default_state();
end
if nargin == 0
varargout = {get_state()};
return
end
if isstruct(message)
set_state(message);
return
end
lmessage = lower(message);
switch lmessage
case {'on', 'off', 'once'}
update_state('when', lmessage);
return
case 'reset'
set_default_state();
return
otherwise
show_warning(message, varargin{:});
end
function show_warning(message, varargin)
[identifier, full_message] = get_identifier_and_message( ...
message, varargin{:});
shown_warnings = get_from_state('shown_warnings');
has_warning = cosmo_match({full_message}, shown_warnings);
if ~has_warning
shown_warnings{end + 1} = full_message;
update_state('shown_warnings', shown_warnings);
end
when = get_from_state('when');
switch when
case 'once'
do_show_warning = ~has_warning;
me = mfilename();
postfix = sprintf(['\n\nThis warning is shown only once, '...
'but the underlying issue may occur '...
'multiple times. To show each warning:\n'...
' - every time: %s(''on'')\n'...
' - once: %s(''once'')\n'...
' - never: %s(''off'')\n'], me, me, me);
full_message = [full_message postfix];
case 'off'
do_show_warning = false;
case 'on'
do_show_warning = true;
otherwise
assert(false);
end
if do_show_warning
state = warning(); % store state
state_resetter = onCleanup(@()warning(state));
warning('on', 'all');
% avoid extra entry on the stack
has_identifier = ~isempty(identifier);
if has_identifier
warning(identifier, '%s', full_message);
else
warning('%s', full_message);
end
end
function [identifier, full_message] = get_identifier_and_message( ...
message, varargin)
args = varargin;
has_identifier = numel(args) > 0 && has_warning_identifier(message);
if has_identifier
identifier = message;
message = args{1};
args = args(2:end);
else
identifier = '';
end
if numel(args) > 0
full_message = sprintf(message, args{:});
else
full_message = message;
end
function tf = has_warning_identifier(s)
alpha_num = '([a-z_A-Z0-9]+)';
pat = sprintf('^%s(:%s)?:%s$', alpha_num, alpha_num, alpha_num);
tf = ~isempty(regexp(s, pat, 'once'));
function s = get_state()
s = get_or_set_state();
function set_state(s)
get_or_set_state(s);
function set_default_state()
s = struct();
s.when = 'once';
s.shown_warnings = cell(0);
set_state(s);
function value = get_from_state(key)
s = get_state();
value = s.(key);
function update_state(key, value)
s = get_state();
s.(key) = value;
set_state(s);
function varargout = get_or_set_state(s)
persistent state
switch nargin
case 0
% get state
if isempty(state)
set_default_state();
end
varargout = {state};
case 1
% set state
state = s;
varargout = {};
otherwise
assert(false);
end