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.23 2004/11/06 02:54:06 scott 0063 % a few further small edits to the help msg -sm 0064 % 0065 % Revision 1.22 2004/11/05 15:23:37 arno 0066 % ,sg 0067 % 0068 % Revision 1.21 2004/11/05 04:10:44 scott 0069 % help msg. -sm 0070 % 0071 % Revision 1.20 2004/06/09 16:30:42 arno 0072 % adding or if several types 0073 % 0074 % Revision 1.19 2003/10/29 16:35:57 arno 0075 % msg typo 0076 % 0077 % Revision 1.18 2003/07/30 23:53:58 arno 0078 % debug multiple return values 0079 % 0080 % Revision 1.17 2003/07/26 00:21:17 arno 0081 % allowing cell array for values 0082 % 0083 % Revision 1.16 2003/06/30 02:10:10 arno 0084 % strmatch exact 0085 % 0086 % Revision 1.15 2003/01/31 02:35:38 arno 0087 % debugging lowercase/upercase problem 0088 % 0089 % Revision 1.14 2002/11/20 01:05:44 arno 0090 % take into account duplicate parameters 0091 % 0092 % Revision 1.13 2002/11/18 17:15:18 arno 0093 % adding float arg (=real) 0094 % 0095 % Revision 1.12 2002/11/15 02:16:50 arno 0096 % header for web 0097 % 0098 % Revision 1.11 2002/09/30 15:29:23 arno 0099 % autorizing cell arrays for types 0100 % 0101 % Revision 1.10 2002/09/30 00:42:08 arno 0102 % debug input arguments 0103 % 0104 % Revision 1.9 2002/07/29 18:00:53 arno 0105 % debugging for NaN 0106 % 0107 % Revision 1.8 2002/07/29 17:24:22 arno 0108 % header 0109 % 0110 % Revision 1.7 2002/07/20 19:10:41 arno 0111 % debugging output 0112 % 0113 % Revision 1.6 2002/07/19 17:58:11 arno 0114 % returning non-matched 'key' 'val' arguments 0115 % 0116 % Revision 1.5 2002/07/19 17:46:53 arno 0117 % g empty if no varargin 0118 % 0119 % Revision 1.4 2002/07/19 16:27:14 arno 0120 % adding ignore mode 0121 % 0122 % Revision 1.3 2002/07/10 02:18:32 arno 0123 % header info 0124 % 0125 % Revision 1.2 2002/07/10 02:17:27 arno 0126 % debugging error message passing 0127 % 0128 % Revision 1.1 2002/07/10 01:03:19 arno 0129 % Initial revision 0130 % 0131 0132 function [g, varargnew] = finputcheck( vararg, fieldlist, callfunc, mode ) 0133 0134 if nargin < 2 0135 help finputcheck; 0136 return; 0137 end; 0138 if nargin < 3 0139 callfunc = ''; 0140 else 0141 callfunc = [callfunc ' ' ]; 0142 end; 0143 if nargin < 4 0144 mode = 'do not ignore'; 0145 end; 0146 NAME = 1; 0147 TYPE = 2; 0148 VALS = 3; 0149 DEF = 4; 0150 SIZE = 5; 0151 0152 varargnew = {}; 0153 % create structure 0154 % ---------------- 0155 if ~isempty(vararg) 0156 vararg = removedup(vararg); 0157 for index=1:length(vararg) 0158 if iscell(vararg{index}) 0159 vararg{index} = {vararg{index}}; 0160 end; 0161 end; 0162 try 0163 g = struct(vararg{:}); 0164 catch 0165 g = [ callfunc 'error: bad ''key'', ''val'' sequence' ]; return; 0166 end; 0167 else 0168 g = []; 0169 end; 0170 0171 for index = 1:size(fieldlist,NAME) 0172 % check if present 0173 % ---------------- 0174 if ~isfield(g, fieldlist{index, NAME}) 0175 g = setfield( g, fieldlist{index, NAME}, fieldlist{index, DEF}); 0176 end; 0177 tmpval = getfield( g, {1}, fieldlist{index, NAME}); 0178 0179 % check type 0180 % ---------- 0181 if ~iscell( fieldlist{index, TYPE} ) 0182 res = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}, ... 0183 fieldlist{index, VALS}, tmpval, callfunc ); 0184 if isstr(res), g = res; return; end; 0185 else 0186 testres = 0; 0187 tmplist = fieldlist; 0188 for it = 1:length( fieldlist{index, TYPE} ) 0189 if ~iscell(fieldlist{index, VALS}) 0190 res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... 0191 fieldlist{index, VALS}, tmpval, callfunc ); 0192 else res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ... 0193 fieldlist{index, VALS}{it}, tmpval, callfunc ); 0194 end; 0195 if ~isstr(res{it}), testres = 1; end; 0196 end; 0197 if testres == 0, 0198 g = res{1}; 0199 for tmpi = 2:length(res) 0200 g = [ g 10 'or ' res{tmpi} ]; 0201 end; 0202 return; 0203 end; 0204 end; 0205 end; 0206 0207 % check if fields are defined 0208 % --------------------------- 0209 allfields = fieldnames(g); 0210 for index=1:length(allfields) 0211 if isempty(strmatch(allfields{index}, fieldlist(:, 1)', 'exact')) 0212 if ~strcmpi(mode, 'ignore') 0213 g = [ callfunc 'error: undefined argument ''' allfields{index} '''']; return; 0214 end; 0215 varargnew{end+1} = allfields{index}; 0216 varargnew{end+1} = getfield(g, {1}, allfields{index}); 0217 end; 0218 end; 0219 0220 0221 function g = fieldtest( fieldname, fieldtype, fieldval, tmpval, callfunc ); 0222 NAME = 1; 0223 TYPE = 2; 0224 VALS = 3; 0225 DEF = 4; 0226 SIZE = 5; 0227 g = []; 0228 0229 switch fieldtype 0230 case { 'integer' 'real' 'boolean' 'float' }, 0231 if ~isnumeric(tmpval) 0232 g = [ callfunc 'error: argument ''' fieldname ''' must be numeric' ]; return; 0233 end; 0234 if strcmpi(fieldtype, 'boolean') 0235 if tmpval ~=0 & tmpval ~= 1 0236 g = [ callfunc 'error: argument ''' fieldname ''' must be 0 or 1' ]; return; 0237 end; 0238 else 0239 if strcmpi(fieldtype, 'integer') 0240 if ~isempty(fieldval) 0241 if (isnan(tmpval) & ~any(isnan(fieldval))) ... 0242 & (~ismember(tmpval, fieldval)) 0243 g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; 0244 end; 0245 end; 0246 else % real or float 0247 if ~isempty(fieldval) 0248 if tmpval < fieldval(1) | tmpval > fieldval(2) 0249 g = [ callfunc 'error: value out of range for argument ''' fieldname '''' ]; return; 0250 end; 0251 end; 0252 end; 0253 end; 0254 0255 0256 case 'string' 0257 if ~isstr(tmpval) 0258 g = [ callfunc 'error: argument ''' fieldname ''' must be a string' ]; return; 0259 end; 0260 if ~isempty(fieldval) 0261 if isempty(strmatch(lower(tmpval), lower(fieldval), 'exact')) 0262 g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return; 0263 end; 0264 end; 0265 0266 0267 case 'cell' 0268 if ~iscell(tmpval) 0269 g = [ callfunc 'error: argument ''' fieldname ''' must be a cell array' ]; return; 0270 end; 0271 0272 0273 case 'struct' 0274 if ~isstruct(tmpval) 0275 g = [ callfunc 'error: argument ''' fieldname ''' must be a structure' ]; return; 0276 end; 0277 0278 0279 case ''; 0280 otherwise, error([ 'finputcheck error: unrecognized type ''' fieldname '''' ]); 0281 end; 0282 0283 % remove duplicates in the list of parameters 0284 % ------------------------------------------- 0285 function cella = removedup(cella) 0286 [tmp indices] = unique(cella(1:2:end)); 0287 if length(tmp) ~= length(cella)/2 0288 fprintf('Warning: duplicate ''key'', ''val'' parameter(s), keeping the last one(s)\n'); 0289 end; 0290 cella = cella(sort(union(indices*2-1, indices*2)));