This file is indexed.

/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