This file is indexed.

/usr/share/lua/5.1/lgi/class.lua is in lua-lgi 0.9.0.20151101.git.885af4-1.

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
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
------------------------------------------------------------------------------
--
--  LGI Support for generic GType objects and interfaces
--
--  Copyright (c) 2010, 2011, 2012, 2013 Pavel Holejsovsky
--  Licensed under the MIT license:
--  http://www.opensource.org/licenses/mit-license.php
--
------------------------------------------------------------------------------

local type, tostring, rawget, rawset, pairs, select,
getmetatable, setmetatable, error, assert
   = type, tostring, rawget, rawset, pairs, select,
   getmetatable, setmetatable, error, assert
local string = require 'string'

local core = require 'lgi.core'
local gi = core.gi
local component = require 'lgi.component'
local record = require 'lgi.record'
local ffi = require 'lgi.ffi'
local ti = ffi.types
local GObject = gi.require 'GObject'

-- Implementation of class and interface component loading.
local class = {
   class_mt = component.mt:clone(
      'class', { '_virtual', '_property', '_signal',
		 '_method', '_constant', '_field' }),
   interface_mt = component.mt:clone(
      'interface', { '_virtual', '_property', '_signal',
		     '_method', '_constant' }),
}

local type_class_peek = core.callable.new {
   addr = GObject.resolve.g_type_class_peek,
   ret = ti.ptr, ti.GType
}
local type_interface_peek = core.callable.new {
   addr = GObject.resolve.g_type_interface_peek,
   ret = ti.ptr, ti.ptr, ti.GType
}

local type_class = component.create(nil, record.struct_mt)
ffi.load_fields(type_class, { { 'g_type', ti.GType } })
local type_instance = component.create(nil, record.struct_mt)
ffi.load_fields(type_instance, { { 'g_class', type_class, ptr = true } })

-- Checks whether given argument is type of this class.
function class.class_mt:is_type_of(instance)
   if type(instance) == 'userdata' then
      local instance_type = core.object.query(instance, 'repo')
      while instance_type do
	 if instance_type == self
	    or instance_type._implements[self._name] == self then
	    return true
	 end
	 instance_type = rawget(instance_type, '_parent')
      end
   end
   return false
end
class.interface_mt.is_type_of = class.class_mt.is_type_of

local function load_signal_name(name)
   name = name:match('^on_(.+)$')
   return name and name:gsub('_', '-')
end

local function load_signal_name_reverse(name)
   return 'on_' .. name:gsub('%-', '_')
end

local function load_vfunc_name(name)
   return name:match('^do_(.+)$')
end

local function load_vfunc_name_reverse(name)
   return 'do_' .. name
end

local function load_method(mi)
   local flags = mi.flags
   if not flags.is_getter and not flags.is_setter then
      return core.callable.new(mi)
   end
end

local function load_properties(info)
   return component.get_category(
      info.properties, nil,
      function(name) return string.gsub(name, '_', '-') end,
      function(name) return string.gsub(name, '%-', '_') end)
end

local function find_constructor(info)
   -- Check that ctor exists and return value conforms to info type.
   local ctor = gi[info.namespace][core.uncamel(info.name)]
   if ctor then
      local ret = ctor.return_type.interface
      for walk in function(_, c) return c.parent end, nil, info do
	 if ret and walk == ret then
	    ctor = core.callable.new(ctor)
	    return function(self, ...) return ctor(...) end
	 end
      end
   end
end

-- Resolver for classes, recursively resolves also all parents and
-- implemented interfaces.
function class.class_mt:_resolve(recursive)
   -- Resolve itself using inherited implementation.
   component.mt._resolve(self)

   -- Go to parent and implemented interfaces and resolve them too.
   if recursive then
      for _, iface in pairs(self._implements or {}) do
	 iface:_resolve(recursive)
      end
      if self._parent then
	 self._parent:_resolve(recursive)
      end
   end
   return self
end

-- _element implementation for objects, checks parent and implemented
-- interfaces if element cannot be found in current typetable.
local internals = { _native = true, _type = true, _gtype = true,
		    _class = true, class = true }
function class.class_mt:_element(instance, symbol)
   -- Special handling of internal symbols.
   if instance and internals[symbol] then return symbol, symbol end

   -- Check default implementation.
   local element, category = component.mt._element(self, instance, symbol)
   if element then return element, category end

   -- Check parent and all implemented interfaces.
   local parent = rawget(self, '_parent')
   if parent then
      element, category = parent:_element(instance, symbol)
      if element then return element, category end
   end
   local implements = rawget(self, '_implements') or {}
   for _, implemented in pairs(implements or {}) do
      element, category = implemented:_element(instance, symbol, self)
      if element then return element, category end
   end
end

-- Implementation of field accessor.  Note that compound fields are
-- not supported in classes (because they are not seen in the wild and
-- I'm lazy).
function class.class_mt:_access_field(instance, field, ...)
   return core.object.field(instance, field, ...)
end

-- Add accessor '_native' handling.
function class.class_mt:_access_native(instance)
   return core.object.query(instance, 'addr')
end

-- Add accessor '_type' handling.
function class.class_mt:_access_type(instance)
   return core.object.query(instance, 'repo')
end

-- Add accessor '_gtype' handling.
function class.class_mt:_access_gtype(instance)
   -- Cast address of the instance to TypeInstance to get to type info.
   local ti = core.record.new(type_instance,
			      core.object.query(instance, 'addr'))
   return ti.g_class.g_type
end

-- Add accessor '_class' handling.
function class.class_mt:_access_class(instance)
   local gtype = class.class_mt._access_gtype(self, instance)
   return core.record.new(self._class, type_class_peek(gtype))
end
class.class_mt._accessclass = class.class_mt._access_class

-- Add accessor '_virtual' handling.
function class.class_mt:_access_virtual(instance, vfi)
   local class_struct
   local container = vfi.container
   if container.is_interface then
      local gtype = class.class_mt._access_gtype(self, instance)
      local ptr = type_interface_peek(type_class_peek(gtype), container.gtype)
      class_struct = core.record.new(core.index[container.gtype]._class, ptr)
   else
      class_struct = class.class_mt._access_class(self, instance)
   end

   -- Retrieve proper method from the class struct.
   return class_struct[vfi.name]
end

-- Add __index for _virtual handling.  Convert vfi baseinfo into real
-- callable pointer according to the target type.
function class.class_mt:_index_virtual(vfi)
   -- Get proper class struct, either from class or interface.
   local ptr, class_struct = type_class_peek(self._gtype)
   if not ptr then return nil end
   local container = vfi.container
   if container.is_interface then
      local gtype = container._gtype
      local ptr = type_interface_peek(ptr, gtype)
      class_struct = core.record.new(core.index[gtype]._class, ptr)
   else
      class_struct = core.record.new(self._class, ptr)
   end

   -- Retrieve proper method from the class struct.
   return class_struct[vfi.name]
end

function class.load_interface(namespace, info)
   -- Load all components of the interface.
   local interface = component.create(info, class.interface_mt)
   interface._property = load_properties(info)
   interface._method = component.get_category(info.methods, load_method)
   interface._signal = component.get_category(
      info.signals, nil, load_signal_name, load_signal_name_reverse)
   interface._constant = component.get_category(info.constants, core.constant)
   local type_struct = info.type_struct
   if type_struct then
      interface._virtual = component.get_category(
	 info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse)
      interface._class = record.load(type_struct)
      interface._class._gtype = interface._gtype
      interface._class._allow = true
      interface._class._parent = core.repo.GObject.TypeInterface
   end
   interface._new = find_constructor(info)
   return interface
end

function class.load_class(namespace, info)
   -- Find parent record, if available.
   local parent_info, parent = info.parent
   if parent_info then
      local ns, name = parent_info.namespace, parent_info.name
      if ns ~= namespace._name or name ~= info.name then
	 parent = core.repo[ns][name]
      end
   end

   -- Create class instance, copy mt from parent, if parent exists,
   -- otherwise defaults to class_mt.
   local class = component.create(
      info, parent and getmetatable(parent) or class.class_mt)
   class._parent = parent
   class._property = load_properties(info)
   class._method = component.get_category(info.methods, load_method)
   class._signal = component.get_category(
      info.signals, nil, load_signal_name, load_signal_name_reverse)
   class._constant = component.get_category(info.constants, core.constant)
   class._field = component.get_category(info.fields)
   local type_struct = info.type_struct
   if type_struct then
      class._virtual = component.get_category(
	 info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse)
      class._class = record.load(type_struct)
      class._class._gtype = class._gtype
      class._class._allow = true
      class._class._parent =
	 parent and parent._class or core.repo.GObject.TypeClass
   end

   -- Populate inheritation information (_implements and _parent fields).
   local interfaces, implements = info.interfaces, {}
   for i = 1, #interfaces do
      local iface = interfaces[i]
      implements[iface.fullname] = core.repo[iface.namespace][iface.name]
   end
   class._implements = implements
   class._new = find_constructor(info)
   return class
end

local register_static = core.callable.new(GObject.type_register_static)
local type_query = core.callable.new(GObject.type_query)
local type_add_interface_static = core.callable.new(
   GObject.type_add_interface_static)
function class.class_mt:derive(typename, ifaces)
   -- Prepare repotable for newly registered class.
   local new_class = setmetatable(
      {
	 _parent = self, _override = {}, _guard = {}, _implements = {},
	 _property = {}, _element = class.derived_mt._element,
	 _property_get = {}, _property_set = {},
	 _class = self._class, _name = typename
      },
      class.derived_mt)

   -- Create class-initialization closure, which assigns pointers to
   -- all known overriden virtual methods.
   local function class_init(class_addr)
      -- Create instance of real class.
      local class_struct = core.record.new(new_class._class, class_addr)

      -- Iterate through all overrides and assign to the virtual callbacks.
      for name, addr in pairs(new_class._override) do
	 if type(addr) == 'userdata' then
	    class_struct[name] = addr
	 end
      end

      -- If type specified _class_init method, invoke it.
      local _class_init = new_class._class_init
      if _class_init then
	 _class_init(new_class, class_struct)
      end
   end
   local class_init_guard, class_init_addr = core.marshal.callback(
      GObject.ClassInitFunc, class_init)
   new_class._guard._class_init = class_init_guard

   -- Create instance initialization function.  Note that we do not
   -- pass directly user's method, because user will probably set it
   -- later after the type is already created, but we need to pass its
   -- address right now during type initialization.  Therefore, a stub
   -- which looks up the init method of the type dynamically is used
   -- instead.
   local function instance_init(instance)
      local _init = rawget(new_class, '_init')
      if _init then
	 -- Convert instance to real type and call init with it.
	 _init(core.object.new(core.record.query(instance, 'addr'),
	       false, true))
      end
   end
   local instance_init_guard, instance_init_addr = core.marshal.callback(
      GObject.InstanceInitFunc, instance_init)
   new_class._guard._instance_init = instance_init_guard

   -- Prepare GTypeInfo with the registration.
   local parent_info = type_query(self._gtype)
   local type_info = core.repo.GObject.TypeInfo {
      class_size = parent_info.class_size,
      class_init = class_init_addr,
      instance_size = parent_info.instance_size,
      instance_init = instance_init_addr,
   }

   -- Create the name to register with the GType system.
   local g_typename = typename:gsub('%.', '') .. core.id

   -- Register new type with GType system.
   local gtype = register_static(self._gtype, g_typename, type_info, {})
   rawset(new_class, '_gtype', core.gtype(gtype))
   if not new_class._gtype then
      error(("failed to derive `%s' from `%s'"):format(typename, self._name))
   end

   -- Add newly registered type into the lgi type index.
   core.index[new_class._gtype] = new_class

   -- Create interface initialization closures.
   for _, iface in pairs(ifaces or {}) do
      local override = {}
      new_class._override[iface._name] = override
      new_class._implements[iface._name] = iface

      -- Prepare interface initialization closure.
      local function iface_init(iface_addr)
	 local iface_struct = core.record.new(iface._class, iface_addr)

	 -- Iterate through all interface overrides and assign to the
	 -- virtual callbacks.
	 for name, addr in pairs(override) do
	    iface_struct[name] = addr
	 end
      end
      local iface_init_guard, iface_init_addr = core.marshal.callback(
	 GObject.InterfaceInitFunc, iface_init)
      new_class._guard['_iface_init_' .. iface._name] = iface_init_guard

      -- Hook up interface to the registered class.
      local iface_info = core.repo.GObject.InterfaceInfo {
	 interface_init = iface_init_addr,
      }
      type_add_interface_static(new_class, iface, iface_info)
   end

   return new_class
end

class.derived_mt = class.class_mt:clone('derived', {})

-- Support for 'priv' pseudomember, holding table with user
-- implementation data.
function class.derived_mt:_element(instance, symbol)
   -- Special handling of 'priv' attribute.
   if instance and symbol == 'priv' then return symbol, '_priv' end

   -- Check default implementation.
   local element, category = class.class_mt._element(self, instance, symbol)
   if element then return element, category end
end

function class.derived_mt:_access_priv(instance, name, ...)
   if select('#', ...) > 0 then
      error(("%s: cannot assign `%s'"):format(self._name, name), 5)
   end
   return core.object.env(instance)
end

-- Overload __newindex to catch assignment to virtual - this causes
-- installation of new virtual method
function class.derived_mt:__newindex(name, target)
   -- Use _element method to get category to write to.
   local _element = (rawget(self, '_element')
		  or rawget(getmetatable(self), '_element'))
   local value, category = _element(self, nil, name)

   if category == '_virtual' then
      -- Overriding virtual method. Prepare callback to the target and
      -- store it to the _override type helper subtable.
      name = load_vfunc_name(name)
      local container = value.container
      local class_struct, override
      if container.is_interface then
	 class_struct = core.index[container.gtype]
	 override = self._override[class_struct._name]
	 class_struct = class_struct._class
      else
	 class_struct = self._class
	 override = self._override
      end
      local guard, vfunc = core.marshal.callback(
	 class_struct[name].callable, target)
      override[name] = vfunc
      self._guard[container.name .. ':' .. name] = guard
   else
      -- Simply assign to type.  This most probably means adding new
      -- member function to the class (or some static member).
      rawset(self, name, target)
   end
end

return class