This file is indexed.

/usr/share/lua/5.1/tongue/langpack.lua is in lua-tongue 0.8-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
-- lib/tongue/langpack.lua
--
-- Lua I18N library 'Tongue' - Language Packs
--
-- Copyright 2016 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--

--- Language packs comprise zero or more sources of translations for a given
-- "language".
--
-- Packs may be added to at any time.  A pack can have a parent pack which will
-- be used if the pack in question lacks a translation token.  Tongue defines a
-- single default pack (available as tongue.pack.fallback) which always returns
-- a string comprising the token and its arguments flattened as strings.  This
-- is the only part of Tongue which assumes an ability to flatten token
-- arguments as strings, all other parts of tongue preserve token arguments
-- unchanged which allows the passing of complex arguments such as repository
-- objects.
--
-- @module tongue.langpack

local fallback, langpack = nil, {}

--- Fallback language pack.
--
-- The fallback language pack provides a mechanism to ensure that language
-- packs can always expand a translation to some extent.
--
-- @field fallback

--- Try and convert a string to a function.
--
-- This takes a tongue expansion string and tries to convert it to a function
-- which can be used to generate the expansion later.
--
-- @tparam string expn The expansion string
-- @treturn[1] function The resulting function
-- @treturn[2] nil To indicate error
-- @treturn[2] string Error message
local function try_convert(expn)
   local expn_t = {}
   local pstate = "normal"
   local acc = ""
   local function transacc(repl)
      if acc ~= "" then
	 expn_t[#expn_t+1] = acc
      end
      acc = repl or ""
   end
   local parser = {
      normal = function(ch)
	 if ch == "$" then
	    pstate = "dollar"
	 else
	    acc = acc .. ch
	 end
      end,
      dollar = function(ch)
	 if ch == "{" then
	    pstate = "getname"
	    transacc({type="arg", name=""})
	 elseif ch == "(" then
	    pstate = "getexpn"
	    transacc({type="expn", name=""})
	 else
	    acc = acc .. "$" .. ch
	    pstate = "normal"
	 end
      end,
      getname = function(ch)
	 if ch == "}" then
	    transacc()
	    pstate = "normal"
	 else
	    acc.name = acc.name .. ch
	 end
      end,
      getexpn = function(ch)
	 if ch == ")" then
	    transacc()
	    pstate = "normal"
	 elseif ch == "," then
	    pstate = "getarg"
	    acc[#acc+1] = ""
	 else
	    acc.name = acc.name .. ch
	 end
      end,
      getarg = function(ch)
	 if ch == ")" then
	    transacc()
	    pstate = "normal"
	 elseif ch == "=" then
	    pstate = "getvalue"
	    acc[#acc] = {k=acc[#acc],v=""}
	 elseif ch == "," then
	    acc[#acc+1] = ""
	 else
	    acc[#acc] = acc[#acc] .. ch
	 end
      end,
      getvalue = function(ch)
	 if ch == ")" then
	    transacc()
	    pstate = "normal"
	 elseif ch == "," then
	    pstate = "getarg"
	    acc[#acc+1] = ""
	 else
	    acc[#acc].v = acc[#acc].v .. ch
	 end
      end,
   }
   for ch in expn:gmatch("(.)") do
      local fn = parser[pstate]
      if fn == nil then
	 return nil, "Unexpected parse state: " .. tostring(pstate)
      end
      fn(ch)
   end
   if pstate ~= "normal" then
      return nil, "Unexpected end of string parsing expansion expression"
   end
   transacc()
   -- Now we need to validate the expansion table
   -- Simple rules on expansion expressions:
   -- 1. must have a name
   -- 2. every argument must have a name (str) or a key/value (tab)
   -- 3. maximum of one ... as a name, not a key/value
   -- 4. any key/value must have the key and value be non-empty
   for _, t in ipairs(expn_t) do
      if type(t) == "string" then
	 -- Nothing to check here
      else
	 if t.name == "" then
	    return nil, "Empty name in expansion expression"
	 end
	 local found_dotdotdot = false
	 if t.type == "expn" then
	    for _, tt in ipairs(t) do
	       if tt == "..." then
		  if found_dotdotdot then
		     return nil, "Repeated ... in expansion expression"
		  end
		  found_dotdotdot = true
	       elseif type(tt) == "table" then
		  if tt.k == "" or tt.v == "" then
		     return nil, "Empty key or value in expansion expression"
		  end
		  if tt.k == "..." then
		     return nil, "Use of ... in key=value expansion expression"
		  end
	       end
	    end
	 else
	    -- Nothing to check here, arg expansions are simple
	 end
      end
   end
   -- Okay, so superficially things look good, wrapper it up in a function
   local function processed_expansion(args)
      -- Note: this closes over expn_t from the outer function
      local ret = {}
      for _, t in ipairs(expn_t) do
	 if type(t) == "string" then
	    ret[#ret+1] = t
	 elseif t.type == "expn" then
	    -- We're "recursing"...
	    local token = t.name
	    local nargs = {}
	    for _, tt in ipairs(t) do
	       if type(tt) == "string" then
		  if tt == "..." then
		     for k, v in pairs(args) do
			nargs[k] = v
		     end
		  else
		     nargs[tt] = args[tt]
		  end
	       else
		  nargs[tt.k] = tt.v
	       end
	    end
	    nargs._pack = args._pack
	    ret[#ret+1] = args._pack:expand(token, nargs)
	 else
	    -- Argument expansion
	    ret[#ret+1] = args[t.name] or ""
	 end
      end
      return table.concat(ret, "")
   end
   return processed_expansion
end

--- Generate a function to localise when a conversion failed.
--
-- This generates a function to report a failed expansion and why
--
-- @tparam string token The token which failed to expand.
-- @tparam string expn The content of that token.
-- @tparam string msg The error message.
-- @treturn function a function which can report that failure
local function report_conversion(token, expn, msg)
   return function(args)
      local nargs = {
	 _pack = args.pack,
	 token = token,
	 expn = expn,
	 msg = msg,
	 args = args
      }
      return args._pack:expand("__TONGUE.FAILEDEXPAND", nargs)
   end
end


--- Tongue Language Pack.
--
-- A Tongue language pack comprises zero or more translations associated with
-- the language (and sub-language) chosen at construction time.  Language packs
-- may have a parent and can be augmented at any time with further
-- translations.
--
-- @type langpack

--- Add a token expansion to a pack.
--
-- This adds the expansion of a token to a tongue language pack.  On addition,
-- if the expansion is a string then it will *NOT* be validated unless the
-- strict argument is set.
--
-- Token names are automatically uppercased in the ASCII charset.
--
-- @tparam string token The token to be expanded
-- @tparam string|function expansion The expansion string (or function)
-- @tparam bool strict Whether to treat a bad expansion string as an error.
-- @treturn bool Whether or not the expansion was successfully added
-- @function add_token

function langpack:add_token(token, expansion, strict)
   if strict and type(expansion) == "string" then
      expansion = try_convert(expansion)
      if not expansion then
	 -- We don't give a reason, we just fail to expand/add
	 return false
      end
   end
   self.entries[token:upper()] = expansion
   return true
end

--- Expand a token and arguments into a message.
--
-- This expands the given token and arguments into a full message.  This will
-- always succeed unless something has gone crazywrong with the internals of
-- tongue or the language packs.
--
-- Passed-in tokens are always uppercased before expansion.
--
-- @tparam string token The token to be expanded
-- @tparam table args Arguments to the token expansion
-- @treturn string The expanded result
-- @function expand
function langpack:expand(token, args)
   local pack = self
   args = args or {}
   if not args._pack then args._pack = pack end
   local ok, expn = pcall(function()
	 if not pack.entries[token] then
	    -- expand upward toward the parent
	    return pack.parent:expand(token, args)
	 end
	 if type(pack.entries[token]) == "string" then
	    -- Attempt to convert the string form into a function
	    local fn, msg = try_convert(pack.entries[token])
	    if not fn then
	       -- Failed to convert, so generate an error report expn. instead
	       fn = report_conversion(token, pack.entries[token], msg)
	    end
	    pack.entries[token] = fn
	 end
	 return pack.entries[token](args)
   end)
   if ok then
      return expn
   end
   -- Failed to expand for whatever reason, we need to report this:
   return self:expand("__TONGUE.INTERNALERROR",
		      { token=token, args=args, err=expn })
end


-- set up the language pack metatable
local langpack_mt = {
   __index = langpack
}

---
-- @section tongue.langpack

--- Create a language pack.
--
-- This creates a tongue language pack.  Once the pack is created it can be
-- populated in various ways by language loaders.  The passed in language
-- is used by other parts of Tongue (e.g. the message resolver) to manage
-- language packs.
--
-- @tparam string language The language name (e.g. 'en')
-- @tparam ?string sublang  The sub-language name (or nil if unwanted) e.g. "GB"
-- @tparam ?langpack parent The parent langauge pack (if nil, Tongue will use the fallback)
-- @treturn langpack The newly created language pack
-- @function create
local function createpack(language, sublang, parent)
   local retpack = {}
   retpack.language = language
   retpack.sublang = sublang
   retpack.parent = parent or fallback
   retpack.entries = {}
   retpack.lang = sublang and language .. "_" .. sublang or language
   return setmetatable(retpack, langpack_mt)
end

-- Finally, populate the fallback pack with some cleverness
fallback = createpack()

local function flatten(t)
   if t._VISITED then return "???" end
   t._VISITED=t
   local ret = {}
   for k, v in pairs(t) do
      if type(k) == "string" and string.sub(k, 1, 1) ~= "_" then
	 if type(v) == "table" then
	    v = flatten(v)
	 elseif type(v) == "string" then
	    v = ("%q"):format(v)
	 else
	    v = tostring(v)
	 end
	 ret[#ret+1] = k .. "=" .. v
      end
   end
   t._VISITED=nil
   return "{" .. table.concat(ret,",") .. "}"
end

local function fallback_entries_index(t, name)
   local f = function(args)
      return "!!!" .. name .. "!!!" .. flatten(args)
   end
   t[name] = f
   return f
end

setmetatable(fallback.entries, {__index=fallback_entries_index})

fallback.entries["__TONGUE.INTERNALERROR"] = function(args)
   -- args.token
   -- args.err
   -- args.args
   return table.concat({
	 "!!!Internal error while processing", tostring(args.token),
	 "-", tostring(args.err), "-", flatten(args.args)}, " ")
end

fallback.entries["__TONGUE.FAILEDEXPAND"] = function(args)
   -- args.token
   -- args.expn
   -- args.msg
   -- args.args
   return table.concat({
	 "!!!Failed to expand", tostring(args.token), "-", tostring(args.expn),
	 "-", tostring(args.msg), "-", flatten(args.args)}, " ")
end

return {
   create = createpack,
   fallback = fallback
}