cm_eeg_finputcheck_20140226.m 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. % finputcheck() - check Matlab function {'key','value'} input argument pairs
  2. %
  3. % Usage: >> result = finputcheck( varargin, fieldlist );
  4. % >> [result varargin] = finputcheck( varargin, fieldlist, ...
  5. % callingfunc, mode, verbose );
  6. % Input:
  7. % varargin - Cell array 'varargin' argument from a function call using 'key',
  8. % 'value' argument pairs. See Matlab function 'varargin'
  9. % fieldlist - A 4-column cell array, one row per 'key'. The first
  10. % column contains the key string, the second its type(s),
  11. % the third the accepted value range, and the fourth the
  12. % default value. Allowed types are 'boolean', 'integer',
  13. % 'real', 'string', 'cell' or 'struct'. For example,
  14. % {'key1' 'string' { 'string1' 'string2' } 'defaultval_key1'}
  15. % {'key2' {'real' 'integer'} { minint maxint } 'defaultval_key2'}
  16. % callingfunc - Calling function name for error messages. {default: none}.
  17. % mode - ['ignore'|'error'] ignore keywords that are either not specified
  18. % in the fieldlist cell array or generate an error.
  19. % {default: 'error'}.
  20. % verbose - ['verbose', 'quiet'] print information. Default: 'verbose'.
  21. %
  22. % Outputs:
  23. % result - If no error, structure with 'key' as fields and 'value' as
  24. % content. If error this output contain the string error.
  25. % varargin - residual varagin containing unrecognized input arguments.
  26. % Requires mode 'ignore' above.
  27. %
  28. % Note: In case of error, a string is returned containing the error message
  29. % instead of a structure.
  30. %
  31. % Example (insert the following at the beginning of your function):
  32. % result = finputcheck(varargin, ...
  33. % { 'title' 'string' [] ''; ...
  34. % 'percent' 'real' [0 1] 1 ; ...
  35. % 'elecamp' 'integer' [1:10] [] });
  36. % if isstr(result)
  37. % error(result);
  38. % end
  39. %
  40. % Note:
  41. % The 'title' argument should be a string. {no default value}
  42. % The 'percent' argument should be a real number between 0 and 1. {default: 1}
  43. % The 'elecamp' argument should be an integer between 1 and 10 (inclusive).
  44. %
  45. % Now 'g.title' will contain the title arg (if any, else the default ''), etc.
  46. %
  47. % Author: Arnaud Delorme, CNL / Salk Institute, 10 July 2002
  48. % Copyright (C) Arnaud Delorme, CNL / Salk Institute, 10 July 2002, arno@salk.edu
  49. %
  50. % This program is free software; you can redistribute it and/or modify
  51. % it under the terms of the GNU General Public License as published by
  52. % the Free Software Foundation; either version 2 of the License, or
  53. % (at your option) any later version.
  54. %
  55. % This program is distributed in the hope that it will be useful,
  56. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  57. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  58. % GNU General Public License for more details.
  59. %
  60. % You should have received a copy of the GNU General Public License
  61. % along with this program; if not, write to the Free Software
  62. % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  63. function [g, varargnew] = cm_eeg_finputcheck_20140226( vararg, fieldlist, callfunc, mode, verbose )
  64. if nargin < 2
  65. help finputcheck;
  66. return;
  67. end;
  68. if nargin < 3
  69. callfunc = '';
  70. else
  71. callfunc = [callfunc ' ' ];
  72. end;
  73. if nargin < 4
  74. mode = 'do not ignore';
  75. end;
  76. if nargin < 5
  77. verbose = 'verbose';
  78. end;
  79. NAME = 1;
  80. TYPE = 2;
  81. VALS = 3;
  82. DEF = 4;
  83. SIZE = 5;
  84. varargnew = {};
  85. % create structure
  86. % ----------------
  87. if ~isempty(vararg)
  88. for index=1:length(vararg)
  89. if iscell(vararg{index})
  90. vararg{index} = {vararg{index}};
  91. end;
  92. end;
  93. try
  94. g = struct(vararg{:});
  95. catch
  96. vararg = removedup(vararg, verbose);
  97. try
  98. g = struct(vararg{:});
  99. catch
  100. g = [ callfunc 'error: bad ''key'', ''val'' sequence' ]; return;
  101. end;
  102. end;
  103. else
  104. g = [];
  105. end;
  106. for index = 1:size(fieldlist,NAME)
  107. % check if present
  108. % ----------------
  109. if ~isfield(g, fieldlist{index, NAME})
  110. g = setfield( g, fieldlist{index, NAME}, fieldlist{index, DEF});
  111. end;
  112. tmpval = getfield( g, {1}, fieldlist{index, NAME});
  113. % check type
  114. % ----------
  115. if ~iscell( fieldlist{index, TYPE} )
  116. res = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}, ...
  117. fieldlist{index, VALS}, tmpval, callfunc );
  118. if isstr(res), g = res; return; end;
  119. else
  120. testres = 0;
  121. tmplist = fieldlist;
  122. for it = 1:length( fieldlist{index, TYPE} )
  123. if ~iscell(fieldlist{index, VALS})
  124. res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ...
  125. fieldlist{index, VALS}, tmpval, callfunc );
  126. else res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ...
  127. fieldlist{index, VALS}{it}, tmpval, callfunc );
  128. end;
  129. if ~isstr(res{it}), testres = 1; end;
  130. end;
  131. if testres == 0,
  132. g = res{1};
  133. for tmpi = 2:length(res)
  134. g = [ g 10 'or ' res{tmpi} ];
  135. end;
  136. return;
  137. end;
  138. end;
  139. end;
  140. % check if fields are defined
  141. % ---------------------------
  142. allfields = fieldnames(g);
  143. for index=1:length(allfields)
  144. if isempty(strmatch(allfields{index}, fieldlist(:, 1)', 'exact'))
  145. if ~strcmpi(mode, 'ignore')
  146. g = [ callfunc 'error: undefined argument ''' allfields{index} '''']; return;
  147. end;
  148. varargnew{end+1} = allfields{index};
  149. varargnew{end+1} = getfield(g, {1}, allfields{index});
  150. end;
  151. end;
  152. function g = fieldtest( fieldname, fieldtype, fieldval, tmpval, callfunc );
  153. NAME = 1;
  154. TYPE = 2;
  155. VALS = 3;
  156. DEF = 4;
  157. SIZE = 5;
  158. g = [];
  159. switch fieldtype
  160. case { 'integer' 'real' 'boolean' 'float' },
  161. if ~isnumeric(tmpval) && ~islogical(tmpval)
  162. g = [ callfunc 'error: argument ''' fieldname ''' must be numeric' ]; return;
  163. end;
  164. if strcmpi(fieldtype, 'boolean')
  165. if tmpval ~=0 && tmpval ~= 1
  166. g = [ callfunc 'error: argument ''' fieldname ''' must be 0 or 1' ]; return;
  167. end;
  168. else
  169. if strcmpi(fieldtype, 'integer')
  170. if ~isempty(fieldval)
  171. if (any(isnan(tmpval(:))) && ~any(isnan(fieldval))) ...
  172. && (~ismember(tmpval, fieldval))
  173. g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return;
  174. end;
  175. end;
  176. else % real or float
  177. if ~isempty(fieldval) && ~isempty(tmpval)
  178. if any(tmpval < fieldval(1)) || any(tmpval > fieldval(2))
  179. g = [ callfunc 'error: value out of range for argument ''' fieldname '''' ]; return;
  180. end;
  181. end;
  182. end;
  183. end;
  184. case 'string'
  185. if ~isstr(tmpval)
  186. g = [ callfunc 'error: argument ''' fieldname ''' must be a string' ]; return;
  187. end;
  188. if ~isempty(fieldval)
  189. if isempty(strmatch(lower(tmpval), lower(fieldval), 'exact'))
  190. g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return;
  191. end;
  192. end;
  193. case 'cell'
  194. if ~iscell(tmpval)
  195. g = [ callfunc 'error: argument ''' fieldname ''' must be a cell array' ]; return;
  196. end;
  197. case 'struct'
  198. if ~isstruct(tmpval)
  199. g = [ callfunc 'error: argument ''' fieldname ''' must be a structure' ]; return;
  200. end;
  201. case '';
  202. otherwise, error([ 'finputcheck error: unrecognized type ''' fieldname '''' ]);
  203. end;
  204. % remove duplicates in the list of parameters
  205. % -------------------------------------------
  206. function cella = removedup(cella, verbose)
  207. % make sure if all the values passed to unique() are strings, if not, exist
  208. %try
  209. [tmp indices] = unique(cella(1:2:end));
  210. if length(tmp) ~= length(cella)/2
  211. myfprintf(verbose,'Note: duplicate ''key'', ''val'' parameter(s), keeping the last one(s)\n');
  212. end;
  213. cella = cella(sort(union(indices*2-1, indices*2)));
  214. %catch
  215. % some elements of cella were not string
  216. % error('some ''key'' values are not string.');
  217. %end;
  218. function myfprintf(verbose, varargin)
  219. if strcmpi(verbose, 'verbose')
  220. fprintf(varargin{:});
  221. end;