/usr/share/octave/packages/general-1.3.4/@inputParser/subsref.m is in octave-general 1.3.4-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | ## Copyright (C) 2011-2012 Carnë Draug <carandraug+dev@gmail.com>
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 3 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, see <http://www.gnu.org/licenses/>.
function inPar = subsref (inPar, idx)
if ( !isa (inPar, 'inputParser') )
error ("object must be of the inputParser class but '%s' was used", class (inPar) );
elseif ( idx(1).type != '.' )
error ("invalid index for class %s", class (inPar) );
endif
## the following at the end may allow to use the obj.method notation one day
## jwe is very against this ugly hack
## what would happen if the user has the obj inside a struct? Bad things!
# ori = inputname(1);
# assignin('caller', ori, inPar);
method = idx(1).subs;
switch method
case 'Results'
inPar = retrieve_results (inPar, idx)
case 'Parameters'
inPar = inPar.Parameters;
case 'parse'
inPar = parse_args (inPar, idx);
case 'Unmatched'
case 'UsingDefaults'
case {'addOptional', 'addParamValue', 'addRequired', 'addSwitch'}
inPar = check_methods (inPar, idx);
otherwise
error ("invalid index for reference of class %s", class (inPar) );
endswitch
## TODO we should make inPar an object of the inputParser class again. At
## least after running parse it becomes just a structure again. While that is
## bad, at least allows for easy access to the Results and Unmatched fields
## without extra coding.
# inPar = class (inPar, 'inputParser');
endfunction
function out = retrieve_results (inPar, idx)
if ( numel(idx) != 2 || idx(2).type != '.' )
print_usage ("@inputParser/Results");
endif
out = inPar.Results.(idx(2).subs);
endfunction
## when parsing options, here's the principle: Required options have to be the
## first ones. They are followed by Optional if any. In the end come the
## ParamValue mixed with Switch. Any other order makes no sense
function inPar = parse_args (inPar, idx)
## syntax is inPar.parse (arguments)
if ( numel(idx) != 2 || idx(2).type != '()' )
print_usage ("@inputParser/parse");
endif
## this makes it easier to read but may be memory instensive
args = idx(2).subs;
## make copy of ordered list of Parameters to keep the original intact and readable
inPar.copy = inPar.Parameters;
if ( numel (fieldnames (inPar.Required)) > numel (args) )
error("%sNot enough arguments", inPar.FunctionName);
endif
## we take names out of 'copy' and values out of 'args', evaluate them and
## store them into 'Results'
for i = 1 : numel (fieldnames (inPar.Required))
[name, inPar.copy] = shift (inPar.copy);
[value, args] = shift (args);
if ( !feval (inPar.Required.(name).validator, value) )
error_invalid (inPar.FunctionName, name, inPar.Required.(name).validator);
endif
inPar.Results.(name) = value;
endfor
## loop a maximum #times of the number of Optional, similarly to the required
## loop. Once ran out of 'args', move their name into usingDefaults, place
## their default values into 'Results', and break
## because if an argument is string and does not validate, should be considered
## a ParamValue key
found_possible_key = false;
for i = 1 : numel (fieldnames (inPar.Optional))
if ( !numel (args) || found_possible_key)
## loops the number of Optional options minus the number of them already processed
for n = 1 : (numel (fieldnames (inPar.Optional)) - i + 1 )
[name, inPar.copy] = shift (inPar.copy);
inPar.UsingDefaults = push (inPar.UsingDefaults, name);
inPar.Results.(name) = inPar.Optional.(name).default;
endfor
break
endif
[name, inPar.copy] = shift (inPar.copy);
[value, args] = shift (args);
if ( !feval (inPar.Optional.(name).validator, value) )
if (ischar (value) )
## maybe the other optional are not defined, this can be Paramvalue
## place this one on defaults and go back to the top with note to clean loop
inPar.UsingDefaults = push (inPar.UsingDefaults, name);
inPar.Results.(name) = inPar.Optional.(name).default;
found_possible_key = true;
args = unshift (args, value);
continue
else
error_invalid (inPar.FunctionName, name, inPar.Optional.(name).validator);
endif
else
inPar.Results.(name) = value;
endif
endfor
## loop a maximum #times of the number of ParamValue, taking pairs of keys and
## values out 'args'. We no longer expect an order so we need the index in
## 'copy' to remove it from there. Once ran out of 'args', move their name
## into usingDefaults, place their default values into 'Results', and break
for i = 1 : (numel (fieldnames (inPar.ParamValue)) + numel (fieldnames (inPar.Switch)))
if ( !numel (args) )
## loops the number of times left in 'copy' since these are the last type
for n = 1 : numel (inPar.copy)
[name, inPar.copy] = shift (inPar.copy);
inPar.UsingDefaults = push (inPar.UsingDefaults, name);
if (isfield (inPar.ParamValue, name))
inPar.Results.(name) = inPar.ParamValue.(name).default;
else
inPar.Results.(name) = inPar.Switch.(name).default;
endif
endfor
break
endif
[key, args] = shift (args);
if ( !ischar (key) )
error("%sParameter/Switch names must be strings", inPar.FunctionName);
endif
if (inPar.CaseSensitive)
index = find( strcmp(inPar.copy, key));
else
index = find( strcmpi(inPar.copy, key));
endif
## we can't use isfield here to support case insensitive
if (any (strcmpi (fieldnames (inPar.Switch), key)))
value = true;
method = "Switch";
else
## then it must be a ParamValue (even if unmatched), shift its value
if (numel (args) < 1)
error ("%sparameter '%s' does not have a value", inPar.FunctionName, key);
endif
[value, args] = shift (args);
method = "ParamValue";
endif
## empty index means no match so either return error or move them into 'Unmatched'
if (!isempty (index))
[name, inPar.copy] = shift (inPar.copy, index);
if ( !feval (inPar.(method).(name).validator, value))
error_invalid (inPar.FunctionName, key, inPar.(method).(name).validator);
endif
## we use the name shifted from 'copy' instead of the key from 'args' in case
## the key is in the wrong case
inPar.Results.(name) = value;
elseif (isempty (index) && inPar.KeepUnmatched )
inPar.Unmatched.(key) = value;
i = i - 1; # this time didn't count, go back one
else
error ("%sargument '%s' did not match any valid parameter of the parser", inPar.FunctionName, key);
endif
endfor
## if there's leftovers they must be unmatched. Note that some unmatched can
## have already been processed in the ParamValue loop
if ( numel (args) && inPar.KeepUnmatched )
for i = 1 : ( numel(args) / 2 )
[key, args] = shift (args);
[value, args] = shift (args);
inPar.Unmatched.(key) = value;
endfor
elseif ( numel (args) )
error("%sfound unmatched parameters at end of arguments list", inPar.FunctionName);
endif
## remove copied field, keep it clean
inPar = rmfield (inPar, 'copy');
endfunction
function inPar = check_methods (inPar, idx)
## this makes it easier to read but is more memory intensive?
method = idx(1).subs;
args = idx(2).subs;
func = sprintf ("@inputParser/%s", method);
if ( idx(2).type != '()' )
print_usage (func);
endif
def_val = @() true;
[name, args] = shift (args);
## a validator is optional but that complicates handling all the parsing with
## few functions and conditions. If not specified @() true will always return
## true. Simply using true is not enough because if the argument is zero it
## return false and if it's too large, takes up memory
switch method
case {'addOptional', 'addParamValue'}
if ( numel (args) == 1 )
args{2} = def_val;
elseif ( numel (args) == 2 )
args{2} = validate_validator (args{2});
else
print_usage(func);
endif
[def, val] = args{:};
case {'addRequired'}
if ( numel (args) == 0 )
val = def_val;
elseif ( numel (args) == 1 )
val = validate_validator (args{1});
else
print_usage(func);
endif
def = false;
case {'addSwitch'}
if ( numel (args) == 0 )
val = def_val;
def = false;
else
print_usage(func);
endif
otherwise
error ("invalid index for reference of class %s", class (inPar) );
endswitch
inPar = validate_args (method(4:end), inPar, name, val, def);
endfunction
## because we are nice we also support using the name of a function and not only
## a function handle
function val = validate_validator (val)
if ( ischar (val) )
val = str2func (val);
elseif ( !isa (val, 'function_handle') )
error ("validator must be a function handle or the name of a valid function");
end
endfunction
## to have a single function that handles them all, something must be done with
## def value, because addRequire does not have those. That's why the order of
## the last two args is different from the rest and why 'def' has a default value
function inPar = validate_args (method, inPar, name, val, def = false)
if ( !strcmp (class (inPar), 'inputParser') )
error ("object must be of the inputParser class but '%s' was used", class (inPar) );
elseif ( !isvarname (name) )
error ("invalid variable name in argname");
endif
## because the order arguments are specified are the order they are expected,
## can't have ParamValue/Switch before Optional, and Optional before Required
n_optional = numel (fieldnames (inPar.Optional));
n_params = numel (fieldnames (inPar.ParamValue));
n_switch = numel (fieldnames (inPar.Switch));
if ( strcmp (method, 'Required') && ( n_optional || n_params || n_switch) )
error ("Can't specify 'Required' arguments after Optional, ParamValue or Switch");
elseif ( strcmp (method, 'Optional') && ( n_params || n_switch) )
error ("Can't specify 'Optional' arguments after ParamValue or Switch");
endif
## even if CaseSensitive is turned on, we still shouldn't have two args with
## the same. What if they decide to change in the middle of specifying them?
if ( any (strcmpi (inPar.Parameters, name)) )
error ("argname '%s' has already been specified", name);
else
inPar.Parameters = push (inPar.Parameters, name);
inPar.(method).(name).default = def;
inPar.(method).(name).validator = val;
endif
## make sure that the given default value is actually valid
## TODO make sure that when using the default, it's only validated once
if ( isa (val, 'function_handle') && !strcmpi (method, 'Required') && !feval (val, def) )
error ("default value for '%s' failed validation with '%s'", name, func2str (val) );
endif
endfunction
## this is just for consistency of error message
function error_invalid (prefix, name, val)
error("%sargument '%s' failed validation %s", prefix, name, func2str (val));
endfunction
################################################################################
## very auxiliary functions
################################################################################
function [out, in] = shift (in, idx = 1)
out = in{idx};
in(idx) = [];
endfunction
function [in] = unshift (in, add)
if ( !iscell (add) )
add = {add};
endif
in (numel(add) + 1 : end + numel(add)) = in;
in (1:numel(add)) = add;
endfunction
function [in] = push (in, add)
if ( !iscell (add) )
add = {add};
endif
in( end+1 : end+numel(add) ) = add;
endfunction
|