-
Notifications
You must be signed in to change notification settings - Fork 0
/
parseInputs.m
159 lines (130 loc) · 5.11 KB
/
parseInputs.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
function[varargout] = parseInputs( inArgs, flags, defaults, switches )
%% Parses inputs for (string-flag, value) input pairs and for boolean string switches.
%
% [values] = parseInputs( inArgs, flags, defaults, switches )
%
%
% ----- Inputs -----
%
% inArgs: typically, varargin{:} for a function calla
%
% flags: All the possible string flags
%
% defaults: The default value for the value associated with each string flag
%
% switches: A cell of allowed strings for string switches, OR a 'b' character for
% boolean string switches, OR an empty cell if neither of these
% options is applicable.
%
%
% ----- Outputs -----
%
% values: The values for each string flag in order of flag input.
%
%
% ----- Author -----
%
% Jonathan King, 2017, University of Arizona, [email protected]
% Make sure everything is formatted correctly
errorCheck(flags, defaults, switches);
% Initialize output to default values
varargout = defaults;
% If inputs were specified...
if ~isempty( inArgs )
% An array to record whether a value has been set already
setValue = false(length(flags));
% Record whether an arg is a flag or a value
valueID = NaN;
% For each input argument
for k = 1:length(inArgs)
% Get the current arg
arg = inArgs{k};
% If this is a value...
if ~isnan(valueID)
% If this is a string switch...
if ~isempty(switches{valueID})
% Check that this is a string...
if ~ischar(arg) || ~isvector(arg)
error('The value following ''%s'' is not a string.',flags{valueID});
% ...and that it is an allowed string.
elseif ~any( strcmpi( arg, switches{valueID} ) );
error('The input following ''%s'' is not a recognized string.', flags{valueID});
end
end
% ...record in the output array.
varargout{valueID} = arg;
% Note that this value has been set by the user
setValue(valueID) = true;
% Next input is not a value, return valueID to NaN
valueID = NaN;
% Otherwise, this is a string flag
else
% Get the identity of the string
valueID = find( strcmpi(arg, flags) );
% If the arg does not match a flag, it is unrecognized
if isempty(valueID)
error('Unrecognized input...');
end
% Check that this flag has not already been set
if setValue( valueID )
error('The ''%s'' value is being set multiple times.',arg);
end
% If this is a boolean switch...
if isequal(switches{valueID}, 'b')
% Set value to the opposite of default
varargout{valueID} = ~varargout{valueID};
setValue(valueID) = true;
valueID = NaN;
end
end
end
% Ensure that there is no "hanging" flag
if ~isnan(valueID)
error('There is no value following ''%s''.',flags{valueID});
end
end
end
function[] = errorCheck(flags, defaults, switches)
% Ensure that everything is formatted properly.
% Ensure that flags, defaults and switches are all cell vectors
if ~iscell(flags) || ~isvector(flags)
error('flags must be a cell vector.');
elseif ~iscell(defaults) || ~isvector(defaults)
error('defaults must be a cell vector.');
elseif ~iscell(switches) || ~isvector(switches)
error('switches must be a cell vector.');
end
% Ensure that the number of flags, defaults, and switch values match
if length(flags)~=length(defaults) || length(flags)~=length(switches)
error('The number of flags, defaults, and switches do not match.');
end
% Ensure that all flags are strings
for k = 1:length(flags)
if ~ischar(flags{k}) || ~isvector(flags{k})
error('All flags must be strings.');
end
% And that no flags are duplicates
if sum( ismember(flags{k}, flags ) ) > 1
error('Duplicate flags are not allowed.');
end
end
% Ensure that all switches are {}, 'b', or a cell vector of strings
for k = 1:length(switches)
if isempty(switches{k})
% Do nothing
elseif isequal(switches{k}, 'b')
% Ensure that the default is a boolean
if ~islogical( defaults{k} )
error('''%s'' is a boolean switch, but its default value is not a boolean.',flags{k});
end
elseif iscell(switches{k}) && isvector(switches{k})
for j = 1:length(switches{k})
if ~ischar(switches{k}{j}) || ~isvector(switches{k}{j})
error('switches(%0.f) contains non-string values',k)
end
end
else
error('Unrecognized value in switches. All switches must be {}, ''b'' or a cell vecctor of strings.');
end
end
end