finputcheck() - check Matlab function {'key','value'} input argument pairs Usage: >> result = finputcheck( varargin, fieldlist ); >> [result varargin] = finputcheck( varargin, fieldlist, ... callingfunc, mode ); Input: varargin - 'varargin' argument from a function call using 'key', 'value' argument pairs. fieldlist - A 3- to 5-column cell array, one row per 'key'. The first column contains the key string, the second its type, 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' 'int' { 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'}. 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: g = finputcheck(varargin, ... { 'title' 'string' [] ''; ... 'percent' 'real' [0 1] 1 ; ... 'elecamp' 'integer' [1:10] [] }); 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 ); 0006 % Input: 0007 % varargin - 'varargin' argument from a function call using 'key', 'value' 0008 % argument pairs. 0009 % fieldlist - A 3- to 5-column cell array, one row per 'key'. The first 0010 % column contains the key string, the second its type, 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' 'int' { 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 % Outputs: 0021 % result - If no error, structure with 'key' as fields and 'value' as 0022 % content. If error this output contain the string error. 0023 % varargin - residual varagin containing unrecognized input arguments. 0024 % Requires mode 'ignore' above. 0025 % 0026 % Note: In case of error, a string is returned containing the error message 0027 % instead of a structure. 0028 % 0029 % Example: 0030 % g = finputcheck(varargin, ... 0031 % { 'title' 'string' [] ''; ... 0032 % 'percent' 'real' [0 1] 1 ; ... 0033 % 'elecamp' 'integer' [1:10] [] }); 0034 % Note: 0035 % The 'title' argument should be a string. {no default value} 0036 % The 'percent' argument should be a real number between 0 and 1. {default: 1} 0037 % The 'elecamp' argument should be an integer between 1 and 10 (inclusive). 0038 % 0039 % Now 'g.title' will contain the title arg (if any, else the default ''), etc. 0040 % 0041 % Author: Arnaud Delorme, CNL / Salk Institute, 10 July 2002 0042 0043 %123456789012345678901234567890123456789012345678901234567890123456789012 0044 0045 % Copyright (C) Arnaud Delorme, CNL / Salk Institute, 10 July 2002, arno@salk.edu 0046 % 0047 % This program is free software; you can redistribute it and/or modify 0048 % it under the terms of the GNU General Public License as published by 0049 % the Free Software Foundation; either version 2 of the License, or 0050 % (at your option) any later version. 0051 % 0052 % This program is distributed in the hope that it will be useful, 0053 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0054 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0055 % GNU General Public License for more details. 0056 % 0057 % You should have received a copy of the GNU General Public License 0058 % along with this program; if not, write to the Free Software 0059 % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0060 0061 % $Log: finputcheck.m,v $ 0062 % Revision 1.24 2006/03/11 05:37:07 arno 0063 % header 0064 % 0065 % Revision 1.23 2004/11/06 02:54:06 scott 0066 % a few further small edits to the help msg -sm 0067 % 0068 % Revision 1.22 2004/11/05 15:23:37 arno 0069 % ,sg 0070 % 0071 % Revision 1.21 2004/11/05 04:10:44 scott 0072 % help msg. -sm 0073 % 0074 % Revision 1.20 2004/06/09 16:30:42 arno 0075 % adding or if several types 0076 % 0077 % Revision 1.19 2003/10/29 16:35:57 arno 0078 % msg typo 0079 % 0080 % Revision 1.18 2003/07/30 23:53:58 arno 0081 % debug multiple return values 0082 % 0083 % Revision 1.17 2003/07/26 00:21:17 arno 0084 % allowing cell array for values 0085 % 0086 % Revision 1.16 2003/06/30 02:10:10 arno 0087 % strmatch exact 0088 % 0089 % Revision 1.15 2003/01/31 02:35:38 arno 0090 % debugging lowercase/upercase problem 0091 % 0092 % Revision 1.14 2002/11/20 01:05:44 arno 0093 % take into account duplicate parameters 0094 % 0095 % Revision 1.13 2002/11/18 17:15:18 arno 0096 % adding float arg (=real) 0097 % 0098 % Revision 1.12 2002/11/15 02:16:50 arno 0099 % header for web 0100 % 0101 % Revision 1.11 2002/09/30 15:29:23 arno 0102 % autorizing cell arrays for types 0103 % 0104 % Revision 1.10 2002/09/30 00:42:08 arno 0105 % debug input arguments 0106 % 0107 % Revision 1.9 2002/07/29 18:00:53 arno 0108 % debugging for NaN 0109 % 0110 % Revision 1.8 2002/07/29 17:24:22 arno 0111 % header 0112 % 0113 % Revision 1.7 2002/07/20 19:10:41 arno 0114 % debugging output 0115 % 0116 % Revision 1.6 2002/07/19 17:58:11 arno 0117 % returning non-matched 'key' 'val' arguments 0118 % 0119 % Revision 1.5 2002/07/19 17:46:53 arno 0120 % g empty if no varargin 0121 % 0122 % Revision 1.4 2002/07/19 16:27:14 arno 0123 % adding ignore mode 0124 % 0125 % Revision 1.3 2002/07/10 02:18:32 arno 0126 % header info 0127 % 0128 % Revision 1.2 2002/07/10 02:17:27 arno 0129 % debugging error message passing 0130 % 0131 % Revision 1.1 2002/07/10 01:03:19 arno 0132 % Initial revision 0133 % 0134 0135 function [g, varargnew] = finputcheck( vararg, fieldlist, callfunc, mode ) 0136 0137 if nargin < 2 0138 help finputcheck; 0139 return; 0140 end; 0141 if nargin < 3 0142 callfunc = ''; 0143 else 0144 callfunc = [callfunc ' ' ]; 0145 end; 0146 if nargin < 4 0147 mode = 'do not ignore'; 0148 end; 0149 NAME = 1; 0150 TYPE = 2; 0151 VALS = 3; 0152 DEF = 4; 0153 SIZE = 5; 0154 0155 varargnew = {}; 0156 % create structure 0157 % ---------------- 0158 if ~isempty(vararg) 0159 vararg = removedup(vararg); 0160 for index=1:length(vararg) 0161 if iscell(vararg{index}) 0162 vararg{index} = {vararg{index}}; 0163 end; 0164 end; 0165 try 0166 g = struct(vararg{:}); 0167 catch 0168 g = [ callfunc 'error: bad ''key'', ''val'' sequence' ]; return; 0169 end; 0170 else 0171 g = []; 0172 end; 0173 0174 for index = 1:size(fieldlist,NAME) 0175 % check if present 0176 % ---------------- 0177 if ~isfield(g, fieldlist{index, NAME}) 0178 g = setfield( g, fieldlist{index, NAME}, fieldlist{index, DEF}); 0179 end; 0180 tmpval = getfield( g, {1}, fieldlist{index, NAME}); 0181 0182 % check type 0183 % ---------- 0184 if ~iscell( fieldlist{index, TYPE} ) 0185 res = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}, ... 0186 fieldlist{index, VALS}, tmpval, callfunc ); 0187 if isstr(res), g = res; return; end; 0188 else 0189 testres = 0; 0190 tmplist = fieldlist; 0191 for it = 1:length( fieldlist{index, TYPE} ) 0192 if ~iscell(fieldlist{index, VALS}) 0193 res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... 0194 fieldlist{index, VALS}, tmpval, callfunc ); 0195 else res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... 0196 fieldlist{index, VALS}{it}, tmpval, callfunc ); 0197 end; 0198 if ~isstr(res{it}), testres = 1; end; 0199 end; 0200 if testres == 0, 0201 g = res{1}; 0202 for tmpi = 2:length(res) 0203 g = [ g 10 'or ' res{tmpi} ]; 0204 end; 0205 return; 0206 end; 0207 end; 0208 end; 0209 0210 % check if fields are defined 0211 % --------------------------- 0212 allfields = fieldnames(g); 0213 for index=1:length(allfields) 0214 if isempty(strmatch(allfields{index}, fieldlist(:, 1)', 'exact')) 0215 if ~strcmpi(mode, 'ignore') 0216 g = [ callfunc 'error: undefined argument ''' allfields{index} '''']; return; 0217 end; 0218 varargnew{end+1} = allfields{index}; 0219 varargnew{end+1} = getfield(g, {1}, allfields{index}); 0220 end; 0221 end; 0222 0223 0224 function g = fieldtest( fieldname, fieldtype, fieldval, tmpval, callfunc ); 0225 NAME = 1; 0226 TYPE = 2; 0227 VALS = 3; 0228 DEF = 4; 0229 SIZE = 5; 0230 g = []; 0231 0232 switch fieldtype 0233 case { 'integer' 'real' 'boolean' 'float' }, 0234 if ~isnumeric(tmpval) 0235 g = [ callfunc 'error: argument ''' fieldname ''' must be numeric' ]; return; 0236 end; 0237 if strcmpi(fieldtype, 'boolean') 0238 if tmpval ~=0 & tmpval ~= 1 0239 g = [ callfunc 'error: argument ''' fieldname ''' must be 0 or 1' ]; return; 0240 end; 0241 else 0242 if strcmpi(fieldtype, 'integer') 0243 if ~isempty(fieldval) 0244 if (isnan(tmpval) & ~any(isnan(fieldval))) ... 0245 & (~ismember(tmpval, fieldval)) 0246 g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; 0247 end; 0248 end; 0249 else % real or float 0250 if ~isempty(fieldval) 0251 if tmpval < fieldval(1) | tmpval > fieldval(2) 0252 g = [ callfunc 'error: value out of range for argument ''' fieldname '''' ]; return; 0253 end; 0254 end; 0255 end; 0256 end; 0257 0258 0259 case 'string' 0260 if ~isstr(tmpval) 0261 g = [ callfunc 'error: argument ''' fieldname ''' must be a string' ]; return; 0262 end; 0263 if ~isempty(fieldval) 0264 if isempty(strmatch(lower(tmpval), lower(fieldval), 'exact')) 0265 g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; 0266 end; 0267 end; 0268 0269 0270 case 'cell' 0271 if ~iscell(tmpval) 0272 g = [ callfunc 'error: argument ''' fieldname ''' must be a cell array' ]; return; 0273 end; 0274 0275 0276 case 'struct' 0277 if ~isstruct(tmpval) 0278 g = [ callfunc 'error: argument ''' fieldname ''' must be a structure' ]; return; 0279 end; 0280 0281 0282 case ''; 0283 otherwise, error([ 'finputcheck error: unrecognized type ''' fieldname '''' ]); 0284 end; 0285 0286 % remove duplicates in the list of parameters 0287 % ------------------------------------------- 0288 function cella = removedup(cella) 0289 [tmp indices] = unique(cella(1:2:end)); 0290 if length(tmp) ~= length(cella)/2 0291 fprintf('Warning: duplicate ''key'', ''val'' parameter(s), keeping the last one(s)\n'); 0292 end; 0293 cella = cella(sort(union(indices*2-1, indices*2)));