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
0001 % finputcheck() - check Matlab function {'key','value'} input argument pairs 0002 % 0003 % Usage: >> result = finputcheck( varargin, fieldlist ); 0004 % >> [result varargin] = finputcheck( varargin, fieldlist, ... 0005 % callingfunc, mode, verbose ); 0006 % Input: 0007 % varargin - Cell array 'varargin' argument from a function call using 'key', 0008 % 'value' argument pairs. See Matlab function 'varargin' 0009 % fieldlist - A 4-column cell array, one row per 'key'. The first 0010 % column contains the key string, the second its type(s), 0011 % the third the accepted value range, and the fourth the 0012 % default value. Allowed types are 'boolean', 'integer', 0013 % 'real', 'string', 'cell' or 'struct'. For example, 0014 % {'key1' 'string' { 'string1' 'string2' } 'defaultval_key1'} 0015 % {'key2' {'real' 'integer'} { minint maxint } 'defaultval_key2'} 0016 % callingfunc - Calling function name for error messages. {default: none}. 0017 % mode - ['ignore'|'error'] ignore keywords that are either not specified 0018 % in the fieldlist cell array or generate an error. 0019 % {default: 'error'}. 0020 % verbose - ['verbose', 'quiet'] print information. Default: 'verbose'. 0021 % 0022 % Outputs: 0023 % result - If no error, structure with 'key' as fields and 'value' as 0024 % content. If error this output contain the string error. 0025 % varargin - residual varagin containing unrecognized input arguments. 0026 % Requires mode 'ignore' above. 0027 % 0028 % Note: In case of error, a string is returned containing the error message 0029 % instead of a structure. 0030 % 0031 % Example (insert the following at the beginning of your function): 0032 % result = finputcheck(varargin, ... 0033 % { 'title' 'string' [] ''; ... 0034 % 'percent' 'real' [0 1] 1 ; ... 0035 % 'elecamp' 'integer' [1:10] [] }); 0036 % if isstr(result) 0037 % error(result); 0038 % end 0039 % 0040 % Note: 0041 % The 'title' argument should be a string. {no default value} 0042 % The 'percent' argument should be a real number between 0 and 1. {default: 1} 0043 % The 'elecamp' argument should be an integer between 1 and 10 (inclusive). 0044 % 0045 % Now 'g.title' will contain the title arg (if any, else the default ''), etc. 0046 % 0047 % Author: Arnaud Delorme, CNL / Salk Institute, 10 July 2002 0048 0049 % Copyright (C) Arnaud Delorme, CNL / Salk Institute, 10 July 2002, arno@salk.edu 0050 % 0051 % This program is free software; you can redistribute it and/or modify 0052 % it under the terms of the GNU General Public License as published by 0053 % the Free Software Foundation; either version 2 of the License, or 0054 % (at your option) any later version. 0055 % 0056 % This program is distributed in the hope that it will be useful, 0057 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0058 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0059 % GNU General Public License for more details. 0060 % 0061 % You should have received a copy of the GNU General Public License 0062 % along with this program; if not, write to the Free Software 0063 % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0064 0065 function [g, varargnew] = finputcheck( vararg, fieldlist, callfunc, mode, verbose ) 0066 0067 if nargin < 2 0068 help finputcheck; 0069 return; 0070 end; 0071 if nargin < 3 0072 callfunc = ''; 0073 else 0074 callfunc = [callfunc ' ' ]; 0075 end; 0076 if nargin < 4 0077 mode = 'do not ignore'; 0078 end; 0079 if nargin < 5 0080 verbose = 'verbose'; 0081 end; 0082 NAME = 1; 0083 TYPE = 2; 0084 VALS = 3; 0085 DEF = 4; 0086 SIZE = 5; 0087 0088 varargnew = {}; 0089 % create structure 0090 % ---------------- 0091 if ~isempty(vararg) 0092 for index=1:length(vararg) 0093 if iscell(vararg{index}) 0094 vararg{index} = {vararg{index}}; 0095 end; 0096 end; 0097 try 0098 g = struct(vararg{:}); 0099 catch 0100 vararg = removedup(vararg, verbose); 0101 try 0102 g = struct(vararg{:}); 0103 catch 0104 g = [ callfunc 'error: bad ''key'', ''val'' sequence' ]; return; 0105 end; 0106 end; 0107 else 0108 g = []; 0109 end; 0110 0111 for index = 1:size(fieldlist,NAME) 0112 % check if present 0113 % ---------------- 0114 if ~isfield(g, fieldlist{index, NAME}) 0115 g = setfield( g, fieldlist{index, NAME}, fieldlist{index, DEF}); 0116 end; 0117 tmpval = getfield( g, {1}, fieldlist{index, NAME}); 0118 0119 % check type 0120 % ---------- 0121 if ~iscell( fieldlist{index, TYPE} ) 0122 res = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}, ... 0123 fieldlist{index, VALS}, tmpval, callfunc ); 0124 if isstr(res), g = res; return; end; 0125 else 0126 testres = 0; 0127 tmplist = fieldlist; 0128 for it = 1:length( fieldlist{index, TYPE} ) 0129 if ~iscell(fieldlist{index, VALS}) 0130 res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... 0131 fieldlist{index, VALS}, tmpval, callfunc ); 0132 else res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... 0133 fieldlist{index, VALS}{it}, tmpval, callfunc ); 0134 end; 0135 if ~isstr(res{it}), testres = 1; end; 0136 end; 0137 if testres == 0, 0138 g = res{1}; 0139 for tmpi = 2:length(res) 0140 g = [ g 10 'or ' res{tmpi} ]; 0141 end; 0142 return; 0143 end; 0144 end; 0145 end; 0146 0147 % check if fields are defined 0148 % --------------------------- 0149 allfields = fieldnames(g); 0150 for index=1:length(allfields) 0151 if isempty(strmatch(allfields{index}, fieldlist(:, 1)', 'exact')) 0152 if ~strcmpi(mode, 'ignore') 0153 g = [ callfunc 'error: undefined argument ''' allfields{index} '''']; return; 0154 end; 0155 varargnew{end+1} = allfields{index}; 0156 varargnew{end+1} = getfield(g, {1}, allfields{index}); 0157 end; 0158 end; 0159 0160 0161 function g = fieldtest( fieldname, fieldtype, fieldval, tmpval, callfunc ); 0162 NAME = 1; 0163 TYPE = 2; 0164 VALS = 3; 0165 DEF = 4; 0166 SIZE = 5; 0167 g = []; 0168 0169 switch fieldtype 0170 case { 'integer' 'real' 'boolean' 'float' }, 0171 if ~isnumeric(tmpval) && ~islogical(tmpval) 0172 g = [ callfunc 'error: argument ''' fieldname ''' must be numeric' ]; return; 0173 end; 0174 if strcmpi(fieldtype, 'boolean') 0175 if tmpval ~=0 && tmpval ~= 1 0176 g = [ callfunc 'error: argument ''' fieldname ''' must be 0 or 1' ]; return; 0177 end; 0178 else 0179 if strcmpi(fieldtype, 'integer') 0180 if ~isempty(fieldval) 0181 if (any(isnan(tmpval(:))) && ~any(isnan(fieldval))) ... 0182 && (~ismember(tmpval, fieldval)) 0183 g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; 0184 end; 0185 end; 0186 else % real or float 0187 if ~isempty(fieldval) && ~isempty(tmpval) 0188 if any(tmpval < fieldval(1)) || any(tmpval > fieldval(2)) 0189 g = [ callfunc 'error: value out of range for argument ''' fieldname '''' ]; return; 0190 end; 0191 end; 0192 end; 0193 end; 0194 0195 0196 case 'string' 0197 if ~isstr(tmpval) 0198 g = [ callfunc 'error: argument ''' fieldname ''' must be a string' ]; return; 0199 end; 0200 if ~isempty(fieldval) 0201 if isempty(strmatch(lower(tmpval), lower(fieldval), 'exact')) 0202 g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; 0203 end; 0204 end; 0205 0206 0207 case 'cell' 0208 if ~iscell(tmpval) 0209 g = [ callfunc 'error: argument ''' fieldname ''' must be a cell array' ]; return; 0210 end; 0211 0212 0213 case 'struct' 0214 if ~isstruct(tmpval) 0215 g = [ callfunc 'error: argument ''' fieldname ''' must be a structure' ]; return; 0216 end; 0217 0218 0219 case ''; 0220 otherwise, error([ 'finputcheck error: unrecognized type ''' fieldname '''' ]); 0221 end; 0222 0223 % remove duplicates in the list of parameters 0224 % ------------------------------------------- 0225 function cella = removedup(cella, verbose) 0226 % make sure if all the values passed to unique() are strings, if not, exist 0227 %try 0228 [tmp indices] = unique(cella(1:2:end)); 0229 if length(tmp) ~= length(cella)/2 0230 myfprintf(verbose,'Note: duplicate ''key'', ''val'' parameter(s), keeping the last one(s)\n'); 0231 end; 0232 cella = cella(sort(union(indices*2-1, indices*2))); 0233 %catch 0234 % some elements of cella were not string 0235 % error('some ''key'' values are not string.'); 0236 %end; 0237 0238 function myfprintf(verbose, varargin) 0239 0240 if strcmpi(verbose, 'verbose') 0241 fprintf(varargin{:}); 0242 end;