-
Notifications
You must be signed in to change notification settings - Fork 1
/
pvargs.m
120 lines (109 loc) · 4.02 KB
/
pvargs.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
function stOptsOut = pvargs(stDefaults, cPVList)
% pvargs: processes a list of property/value pairs, with defaults
% usage: stOptsOut = pvargs(stDefaults, cPVList)
%
% Arguments
% stDefaults
% A structure with fields for every potential property/value pair
% where field names are the property names and field values are the
% property defaults. Properties without a default value are
% specified as empty ([]).
%
% cPVList
% A cell array of property/value pairs where property names are
% specified before values. Property name processing is case
% insensitive and allows for unambiguous name shortening. Value
% class types are also compared to the class type of the supplied
% defaults. A warning is issued if the classes do not agree.
%
% Outputs
% stOptsOut
% A structure with the same fields as stDefaults but with values
% updated according to the property/value pair list provided.
%
% Example usage:
% Set defaults
% dflts.foo = 1;
% dflts.bar = 'monkey';
% dflts.foofoo = {1, '11'};
%
% Update the values based on a property/value list
% newvals = pvargs(dflts, {'f', 2, 'bar', 'chimp'});
%
% Note, an error will result from the above statement:
% ??? Error using ==> pvargs
% 'f' is ambiguous with: foo, foofoo,
%
% Trying:
% newvals = pvargs(dflts, {'foo', 2, 'bar', 'chimp'});
%
% Gives:
% newvals =
% foo: 2
% bar: 'chimp'
% foofoo: {[1] '11'}
% Todo
% Incorporate value constraints
% Allow for flags.
% preset all the default values;
stOptsOut = stDefaults;
opts = struct([]);
args = cPVList;
if ~isempty(args),
% there are options
if mod(length(args),2) == 0,
optn = 0;
for iOpt = 1:2:length(args),
optn = optn + 1;
param = lower(args{iOpt});
value = args{iOpt+1};
% check that param/value pairs are supplied in the correct
% order - e.g. param first!
if ~ischar(param),
err = sprintf(...
['Error at parameter %d.\n', ...
'Parameter names must be of type CHAR'], optn);
error(err);
end
opts(1).(param) = value;
end;
else
error('optional arguments must be supplied as Param,Value pairs');
end;
end;
if ~isempty(opts),
optnames = fieldnames(opts);
validnames = fieldnames(stDefaults);
for i = 1:length(optnames),
optname = optnames{i};
iOpt = strmatch(lower(optname), lower(validnames), 'exact');
bOptFound = true;
if isempty(iOpt),
% check for shortened param name
iOpt = find(strncmpi(optname, validnames, length(optname)));
if isempty(iOpt),
% the param name is not found
warning('pvargs:IgnoredInvalidParamName',['''' optname ''' is not a valid parameter name. Ignored']);
bOptFound = false;
elseif length(iOpt) > 1,
% the param name is ambiguous with other parameters
ambopts = sprintf('%s, ', validnames{iOpt});
error(['The parameter ''' optname ''' is ambiguous with: ' ambopts(1:end-1)]);
end;
end;
if bOptFound,
stOptsOut.(validnames{iOpt}) = opts.(optname);
vlCls = class(opts.(optname));
dfCls = class(stDefaults.(validnames{iOpt}));
% test to make sure that the class of the supplied value is the same as
% the specified default
if ~strcmpi(dfCls, vlCls),
% since some classes are cross compatible (logical <-> numeric)
% just give a warning
warning('parseopts:ClassMismatch', ...
['The class of the value for ''' validnames{iOpt} ...
''' (' vlCls ') does not match the default (' dfCls ')']);
end;
end;
end;
end;