% finputcheck() - check Matlab function {'key','value'} input argument pairs % % Usage: >> result = finputcheck( varargin, fieldlist ); % >> [result varargin] = finputcheck( varargin, fieldlist, ... % callingfunc, mode, verbose ); % Input: % varargin - Cell array 'varargin' argument from a function call using 'key', % 'value' argument pairs. See Matlab function 'varargin' % fieldlist - A 4-column cell array, one row per 'key'. The first % column contains the key string, the second its type(s), % the third the accepted value range, and the fourth the % default value. Allowed types are 'boolean', 'integer', % 'real', 'string', 'cell' or 'struct'. For example, % {'key1' 'string' { 'string1' 'string2' } 'defaultval_key1'} % {'key2' {'real' 'integer'} { minint maxint } 'defaultval_key2'} % callingfunc - Calling function name for error messages. {default: none}. % mode - ['ignore'|'error'] ignore keywords that are either not specified % in the fieldlist cell array or generate an error. % {default: 'error'}. % verbose - ['verbose', 'quiet'] print information. Default: 'verbose'. % % Outputs: % result - If no error, structure with 'key' as fields and 'value' as % content. If error this output contain the string error. % varargin - residual varagin containing unrecognized input arguments. % Requires mode 'ignore' above. % % Note: In case of error, a string is returned containing the error message % instead of a structure. % % Example (insert the following at the beginning of your function): % result = finputcheck(varargin, ... % { 'title' 'string' [] ''; ... % 'percent' 'real' [0 1] 1 ; ... % 'elecamp' 'integer' [1:10] [] }); % if isstr(result) % error(result); % end % % Note: % The 'title' argument should be a string. {no default value} % The 'percent' argument should be a real number between 0 and 1. {default: 1} % The 'elecamp' argument should be an integer between 1 and 10 (inclusive). % % Now 'g.title' will contain the title arg (if any, else the default ''), etc. % % Author: Arnaud Delorme, CNL / Salk Institute, 10 July 2002 % Copyright (C) Arnaud Delorme, CNL / Salk Institute, 10 July 2002, arno@salk.edu % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2 of the License, or % (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program; if not, write to the Free Software % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA function [g, varargnew] = cm_eeg_finputcheck_20140226( vararg, fieldlist, callfunc, mode, verbose ) if nargin < 2 help finputcheck; return; end; if nargin < 3 callfunc = ''; else callfunc = [callfunc ' ' ]; end; if nargin < 4 mode = 'do not ignore'; end; if nargin < 5 verbose = 'verbose'; end; NAME = 1; TYPE = 2; VALS = 3; DEF = 4; SIZE = 5; varargnew = {}; % create structure % ---------------- if ~isempty(vararg) for index=1:length(vararg) if iscell(vararg{index}) vararg{index} = {vararg{index}}; end; end; try g = struct(vararg{:}); catch vararg = removedup(vararg, verbose); try g = struct(vararg{:}); catch g = [ callfunc 'error: bad ''key'', ''val'' sequence' ]; return; end; end; else g = []; end; for index = 1:size(fieldlist,NAME) % check if present % ---------------- if ~isfield(g, fieldlist{index, NAME}) g = setfield( g, fieldlist{index, NAME}, fieldlist{index, DEF}); end; tmpval = getfield( g, {1}, fieldlist{index, NAME}); % check type % ---------- if ~iscell( fieldlist{index, TYPE} ) res = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}, ... fieldlist{index, VALS}, tmpval, callfunc ); if isstr(res), g = res; return; end; else testres = 0; tmplist = fieldlist; for it = 1:length( fieldlist{index, TYPE} ) if ~iscell(fieldlist{index, VALS}) res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... fieldlist{index, VALS}, tmpval, callfunc ); else res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... fieldlist{index, VALS}{it}, tmpval, callfunc ); end; if ~isstr(res{it}), testres = 1; end; end; if testres == 0, g = res{1}; for tmpi = 2:length(res) g = [ g 10 'or ' res{tmpi} ]; end; return; end; end; end; % check if fields are defined % --------------------------- allfields = fieldnames(g); for index=1:length(allfields) if isempty(strmatch(allfields{index}, fieldlist(:, 1)', 'exact')) if ~strcmpi(mode, 'ignore') g = [ callfunc 'error: undefined argument ''' allfields{index} '''']; return; end; varargnew{end+1} = allfields{index}; varargnew{end+1} = getfield(g, {1}, allfields{index}); end; end; function g = fieldtest( fieldname, fieldtype, fieldval, tmpval, callfunc ); NAME = 1; TYPE = 2; VALS = 3; DEF = 4; SIZE = 5; g = []; switch fieldtype case { 'integer' 'real' 'boolean' 'float' }, if ~isnumeric(tmpval) && ~islogical(tmpval) g = [ callfunc 'error: argument ''' fieldname ''' must be numeric' ]; return; end; if strcmpi(fieldtype, 'boolean') if tmpval ~=0 && tmpval ~= 1 g = [ callfunc 'error: argument ''' fieldname ''' must be 0 or 1' ]; return; end; else if strcmpi(fieldtype, 'integer') if ~isempty(fieldval) if (any(isnan(tmpval(:))) && ~any(isnan(fieldval))) ... && (~ismember(tmpval, fieldval)) g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; end; end; else % real or float if ~isempty(fieldval) && ~isempty(tmpval) if any(tmpval < fieldval(1)) || any(tmpval > fieldval(2)) g = [ callfunc 'error: value out of range for argument ''' fieldname '''' ]; return; end; end; end; end; case 'string' if ~isstr(tmpval) g = [ callfunc 'error: argument ''' fieldname ''' must be a string' ]; return; end; if ~isempty(fieldval) if isempty(strmatch(lower(tmpval), lower(fieldval), 'exact')) g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; end; end; case 'cell' if ~iscell(tmpval) g = [ callfunc 'error: argument ''' fieldname ''' must be a cell array' ]; return; end; case 'struct' if ~isstruct(tmpval) g = [ callfunc 'error: argument ''' fieldname ''' must be a structure' ]; return; end; case ''; otherwise, error([ 'finputcheck error: unrecognized type ''' fieldname '''' ]); end; % remove duplicates in the list of parameters % ------------------------------------------- function cella = removedup(cella, verbose) % make sure if all the values passed to unique() are strings, if not, exist %try [tmp indices] = unique(cella(1:2:end)); if length(tmp) ~= length(cella)/2 myfprintf(verbose,'Note: duplicate ''key'', ''val'' parameter(s), keeping the last one(s)\n'); end; cella = cella(sort(union(indices*2-1, indices*2))); %catch % some elements of cella were not string % error('some ''key'' values are not string.'); %end; function myfprintf(verbose, varargin) if strcmpi(verbose, 'verbose') fprintf(varargin{:}); end;