This file is indexed.

/usr/share/lua/5.1/cliargs/parser.lua is in lua-cliargs 3.0-1-3.

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
local K = require 'cliargs.constants'

-------------------------------------------------------------------------------
-- UTILS
-------------------------------------------------------------------------------
local shallow_copy = require 'cliargs.utils.shallow_copy'
local filter = require 'cliargs.utils.filter'
local disect_argument = require 'cliargs.utils.disect_argument'
local lookup = require 'cliargs.utils.lookup'

local function clone_table_shift(t)
  local clone = shallow_copy(t)
  table.remove(clone, 1)
  return clone
end

local function clone_table_remove(t, index)
  local clone = shallow_copy(t)
  table.remove(clone, index)
  return clone
end

-------------------------------------------------------------------------------
-- PARSE ROUTINES
-------------------------------------------------------------------------------
local p = {}
function p.invoke_command(args, options, done)
  local commands = filter(options, 'type', K.TYPE_COMMAND)

  for index, opt in ipairs(args) do
    local command = filter(commands, '__key__', opt)[1]

    if command then
      local command_args = clone_table_remove(args, index)

      if command.__action__ then
        local parsed_command_args, err = command:parse(command_args)

        if err then
          return nil, err
        end

        return command.__action__(parsed_command_args)
      elseif command.__file__ then
        local filename = command.__file__

        if type(filename) == 'function' then
          filename = filename()
        end

        local run_command_file = function()
          _G.arg = command_args

          local res, err = assert(loadfile(filename))()

          _G.arg = args

          return res, err
        end

        return run_command_file()
      end
    end
  end

  return done()
end

function p.print_help(args, printer, done)
  -- has --help or -h ? display the help listing and abort!
  for _, v in pairs(args) do
    if v == "--help" or v == "-h" then
      return nil, printer.generate_help_and_usage()
    end
  end

  return done()
end

function p.track_dump_request(args, done)
  -- starts with --__DUMP__; set dump to true to dump the parsed arguments
  if args[1] == "--__DUMP__" then
    return done(true, clone_table_shift(args))
  else
    return done(false, args)
  end
end

function p.process_arguments(args, options, done)
  local values = {}
  local cursor = 0
  local argument_cursor = 1
  local argument_delimiter_found = false
  local function consume()
    cursor = cursor + 1

    return args[cursor]
  end

  local required = filter(options, 'type', K.TYPE_ARGUMENT)

  while cursor < #args do
    local curr_opt = consume()
    local symbol, key, value, flag_negated = disect_argument(curr_opt)

    -- end-of-options indicator:
    if curr_opt == "--" then
      argument_delimiter_found = true

    -- an option:
    elseif not argument_delimiter_found and symbol then
      local entry = lookup(key, key, options)

      if not key or not entry then
        local option_type = value and "option" or "flag"

        return nil, "unknown/bad " .. option_type .. ": " .. curr_opt
      end

      if flag_negated and not entry.negatable then
        return nil, "flag '" .. curr_opt .. "' may not be negated using --no-"
      end

      -- a flag and a value specified? that's an error
      if entry.flag and value then
        return nil, "flag " .. curr_opt .. " does not take a value"
      elseif entry.flag then
        value = not flag_negated
      -- an option:
      else
        -- the value might be in the next argument, e.g:
        --
        --     --compress lzma
        if not value then
          -- if the option contained a = and there's no value, it means they
          -- want to nullify an option's default value. eg:
          --
          --    --compress=
          if curr_opt:find('=') then
            value = '__CLIARGS_NULL__'
          else
            -- NOTE: this has the potential to be buggy and swallow the next
            -- entry as this entry's value even though that entry may be an
            -- actual argument/option
            --
            -- this would be a user error and there is no determinate way to
            -- figure it out because if there's no leading symbol (- or --)
            -- in that entry it can be an actual argument. :shrug:
            value = consume()

            if not value then
              return nil, "option " .. curr_opt .. " requires a value to be set"
            end
          end
        end
      end

      table.insert(values, { entry = entry, value = value })

      if entry.callback then
        local altkey = entry.key
        local status, err

        if key == entry.key then
          altkey = entry.expanded_key
        else
          key = entry.expanded_key
        end

        status, err = entry.callback(key, value, altkey, curr_opt)

        if status == nil and err then
          return nil, err
        end
      end

    -- a regular argument:
    elseif argument_cursor <= #required then
      local entry = required[argument_cursor]

      table.insert(values, { entry = entry, value = curr_opt })

      if entry.callback then
        local status, err = entry.callback(entry.key, curr_opt)

        if status == nil and err then
          return nil, err
        end
      end

      argument_cursor = argument_cursor + 1

    -- a splat argument:
    else
      local entry = filter(options, 'type', K.TYPE_SPLAT)[1]

      if entry then
        table.insert(values, { entry = entry, value = curr_opt })

        if entry.callback then
          local status, err = entry.callback(entry.key, curr_opt)

          if status == nil and err then
            return nil, err
          end
        end
      end

      argument_cursor = argument_cursor + 1
    end
  end

  return done(values, argument_cursor - 1)
end

function p.validate(options, arg_count, done)
  local required = filter(options, 'type', K.TYPE_ARGUMENT)
  local splatarg = filter(options, 'type', K.TYPE_SPLAT)[1] or { maxcount = 0 }

  local min_arg_count = #required
  local max_arg_count = #required + splatarg.maxcount

  -- missing any required arguments, or too many?
  if arg_count < min_arg_count or arg_count > max_arg_count then
    if splatarg.maxcount > 0 then
      return nil, (
        "bad number of arguments: " ..
        min_arg_count .. "-" .. max_arg_count ..
        " argument(s) must be specified, not " .. arg_count
      )
    else
      return nil, (
        "bad number of arguments: " ..
        min_arg_count .. " argument(s) must be specified, not " .. arg_count
      )
    end
  end

  return done()
end

function p.collect_results(cli_values, options)
  local results = {}
  local function collect_with_default(entry)
    local entry_values = {}
    local _

    for _, item in ipairs(cli_values) do
      if item.entry == entry then
        table.insert(entry_values, item.value)
      end
    end

    if #entry_values == 0 then
      return type(entry.default) == 'table' and entry.default or { entry.default }
    else
      return entry_values
    end
  end

  local function write(entry, value)
    if entry.key then results[entry.key] = value end
    if entry.expanded_key then results[entry.expanded_key] = value end
  end

  for _, entry in pairs(options) do
    local entry_cli_values = collect_with_default(entry)
    local maxcount = entry.maxcount

    if maxcount == nil then
      maxcount = type(entry.default) == 'table' and 999 or 1
    end

    local entry_value = entry_cli_values

    if maxcount == 1 and type(entry_cli_values) == 'table' then
      -- take the last value
      entry_value = entry_cli_values[#entry_cli_values]

      if entry_value == '__CLIARGS_NULL__' then
        entry_value = nil
      end
    end

    write(entry, entry_value)
  end

  return results
end


return function(arguments, options, printer)
  assert(arguments == nil or type(arguments) == "table",
    "expected an argument table to be passed in, " ..
    "got something of type " .. type(arguments)
  )

  local args = arguments or _G.arg or {}

  -- the spiral of DOOM:
  return p.invoke_command(args, options, function()
    return p.track_dump_request(args, function(dump, args_without_dump)
      return p.print_help(args_without_dump, printer, function()
        return p.process_arguments(args_without_dump, options, function(values, arg_count)
          return p.validate(options, arg_count, function()
            if dump then
              return nil, printer.dump_internal_state(values)
            else
              return p.collect_results(values, options)
            end
          end)
        end)
      end)
    end)
  end)
end