A collection of various things from the Asterisk server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
9.6 KiB

local debugls = function(l) for k, v in pairs(l) do print("dbg: " .. tostring(k) .. " => " .. tostring(v)) end end
-- Not portable
local separate_path = function(path)
for i = #path,1,-1 do
if string.sub(path, i, i) == "/" then
return { dir = string.sub(path, 1, i), file = string.sub(path, i + 1, #path) }
end
end
return { file = path }
end
-- Not portable
local to_dir_name = function(s)
if string.sub(s, #s, #s) ~= "/" then
return s .. "/"
else
return s
end
end
-- Not portable
local abs_filename = function(cwd, path)
if string.sub(path, 1, 1) == "/" then
return path
else
if string.sub(cwd, #cwd, #cwd) ~= "/" then
return to_dir_name(cwd) .. path
else
return to_dir_name(cwd) .. path
end
end
end
-- Not portable
local normalize_abs_path = function(path, isdir)
local names = {}
for nm in string.gmatch(path, "[^/]+") do
names[#names + 1] = nm
end
-- Normalize away `.`
for i = #names,1,-1 do
if names[i] == "." or names[i] == "" then
table.remove(names, i)
end
end
-- Normalize away `..`
while names[1] == ".." do table.remove(names, 1) end
local c = true
while c do
c = false
for i = 1,(#names - 1) do
if names[i + 1] == ".." then
table.remove(names, i)
table.remove(names, i)
c = true
break
end
end
end
if isdir then
return "/" .. table.concat(names, "/") .. "/"
else
return "/" .. table.concat(names, "/")
end
end
local path_size = function(path)
local i = 0
for _ in string.gmatch(path, "[^/]+") do
i = i + 1
end
return i
end
-- Not portable
local is_dir = function(filename)
local c = false
local p = io.popen("[ -d '" .. filename .. "' ] && echo ''")
for l in p:lines() do c = true end
p:close()
return c
end
-- Not portable
local file_exists = function(filename)
local c = false
local p = io.popen("[ -e '" .. filename .. "' ] && echo ''")
for l in p:lines() do c = true end
p:close()
return c
end
-- Not portable
local ls_dir = function(dirpath)
local t = {}
local p = io.popen("ls -A '" .. dirpath .. "'")
for l in p:lines() do t[#t + 1] = l end
p:close()
return t
end
local read_manifest
read_manifest = function(filename, file_table, errout)
local parse_line = function(line, cwd)
local weight_specifier
local filepath
for i = 1,#line do
if string.sub(line, i, i) == " " then
weight_specifier = string.sub(line, 1, i - 1)
filepath = string.sub(line, i + 1, #line)
break
end
end
if weight_specifier == nil and filepath == nil then
return nil
end
-- True if a category is to be weighted as a unit, thereby reducing the effective
-- weight of each of its entries. This flag is meant to be employed for other manifests.
local weight_whole_category = false
-- Indicates that the entry is a directory whose applicable files should be read in.
local directory = false
-- This indicates that the entry is a manifest to be read in.
local manifest = false
-- This is the level to recurse into directories or the `here` case.
-- `nil` indicates unbounded recursion.
local recursion_level = 0
-- When `weight_whole_category` is on, this specifies how deeply the categorical
-- weighting will apply. Again, `nil` is unbounded.
local recursive_weighting_level = 0
local numstr = ""
local symbol_actions =
{
["#"] = function() weight_whole_category = true end,
["?"] = function() manifest = true end,
["/"] = function() if recursion_level ~= nil then recursion_level = recursion_level + 1 end end,
["*"] = function() recursion_level = nil end,
["$"] = function() if recursive_weighting_level ~= nil then recursive_weighting_level = recursive_weighting_level + 1 end end,
["%"] = function() recursive_weighting_level = nil end,
["0"] = true,
["1"] = true,
["2"] = true,
["3"] = true,
["4"] = true,
["5"] = true,
["6"] = true,
["7"] = true,
["8"] = true,
["9"] = true,
["-"] = true,
["."] = true,
["e"] = true,
}
for i = 1,#weight_specifier do
local sym = string.sub(weight_specifier, i, i)
local action = symbol_actions[sym]
if action == true then
numstr = numstr .. sym
elseif action == nil then
else
action()
end
end
local num = tonumber(numstr)
if num == nil then num = 1 end
return
{
weight = num,
manifest = manifest,
catweight = weight_whole_category,
directory = directory,
rclevel = recursion_level,
rcwlevel = recursive_weighting_level,
file = normalize_abs_path(abs_filename(cwd, filepath), false)
}
end
local is_iv_name = function(s) return string.sub(s, -4, -1) == ".ivz" or string.sub(s, -3, -1) == ".iv" end
local descend_dir
descend_dir = function(dirpath, file_table, total_weight, catweight, rclevel, rcwlevel, source)
local ftab = ls_dir(dirpath)
local nrcl
if rclevel == nil then nrcl = nil else nrcl = rclevel - 1 end
if catweight then
if rcwlevel == 0 then
local temp_table = {}
for _,en in pairs(ftab) do
local iv = normalize_abs_path(abs_filename(dirpath, en), false)
if is_dir(iv) and (rclevel == nil or rclevel > 0) then
descend_dir(to_dir_name(iv), temp_table, 1, false, nrcl, 0, source)
elseif is_iv_name(iv) then
temp_table[#temp_table + 1] =
{
file = iv,
-- Will be overwritten by loop below anyway
}
end
end
for _,ent in pairs(temp_table) do
file_table[#file_table + 1] =
{
file = ent.file,
weight = total_weight / #temp_table,
source = source
}
end
else
for _,en in pairs(ftab) do
local iv = normalize_abs_path(abs_filename(dirpath, en))
if is_dir(iv) and (rclevel == nil or rclevel > 0) then
if rcwlevel == nil then
descend_dir(to_dir_name(iv), file_table, total_weight / #ftab, true, nrcl, nil, source)
else
descend_dir(to_dir_name(iv), file_table, total_weight / #ftab, true, nrcl, rcwlevel - 1, source)
end
elseif is_iv_name(iv) then
file_table[#file_table + 1] =
{
file = iv,
weight = total_weight / #ftab,
source = source
}
end
end
end
return total_weight
else
local twc = 0
for _,en in pairs(ftab) do
local iv = normalize_abs_path(abs_filename(dirpath, en))
if is_dir(iv) and (rclevel == nil or rclevel > 0) then
descend_dir(to_dir_name(iv), file_table, total_weight, false, nrcl, 0, source)
elseif is_iv_name(iv) then
twc = twc + total_weight
file_table[#file_table + 1] =
{
file = iv,
weight = total_weight,
source = source
}
end
end
return twc
end
end
if filename == nil then return nil end
local mf = io.open(filename, "r")
if not mf then errout("Could not open manifest " .. filename) return nil end
local total_weight = 0
for line in mf:lines() do
local entry = parse_line(line, separate_path(filename).dir)
if entry == nil then goto endloop end
if entry.manifest then
if not file_exists(entry.file) or is_dir(entry.file) then
errout("warning: file " .. entry.file .. " is not a normal file")
end
local temp_table = {}
local tw = read_manifest(entry.file, temp_table, errout)
if entry.catweight then
total_weight = total_weight + entry.weight
for _,ent in pairs(temp_table) do
file_table[#file_table + 1] =
{
file = ent.file,
weight = entry.weight * ent.weight / tw,
source = ent.source,
}
end
else
for _,ent in pairs(temp_table) do
total_weight = total_weight + entry.weight * ent.weight
file_table[#file_table + 1] =
{
file = ent.file,
weight = entry.weight * ent.weight,
source = ent.source,
}
end
end
else
if not file_exists(entry.file) then
errout("warning: file " .. entry.file .. " does not exist")
end
if is_dir(entry.file) then
total_weight = total_weight + descend_dir(to_dir_name(entry.file), file_table, entry.weight, entry.catweight, entry.rclevel, entry.rcwlevel, { file = entry.file, manifest = normalize_abs_path(filename) })
else
total_weight = total_weight + entry.weight
file_table[#file_table + 1] =
{
file = entry.file,
weight = entry.weight,
source = { file = entry.file, manifest = normalize_abs_path(filename) }
}
end
end
::endloop::
end
mf:close()
return total_weight
end
local assemble_weights = function(entries, errout)
local ivs = {}
for _, ent in pairs(entries) do
if ivs[ent.file] ~= nil then
local sza = path_size(ivs[ent.file].source.file)
local szb = path_size(ent.source.file)
if sza < szb then
ivs[ent.file] = { weight = ent.weight, source = ent.source }
elseif sza == szb then
local namea = ivs[ent.file].source.manifest
local nameb = ent.source.manifest
if namea == nameb then
errout("warning: two conflicting weights for " .. ent.file .. " in " .. namea)
else
errout("warning: two conflicting weights for " .. ent.file .. " in " .. namea .. " and " .. nameb)
end
end
else
ivs[ent.file] = { weight = ent.weight, source = ent.source }
end
end
return ivs
end
local function usage()
print("usage: <this program> <input manifest> <output table>")
end
if arg[1] == nil or arg[2] == nil then
usage()
return
end
local taboutf = io.open(arg[2], "w")
if taboutf == nil then
print("Could not open output file")
return
end
local tab = {}
read_manifest(arg[1], tab, function(s) print(s) end)
local weightmap = assemble_weights(tab, function(s) print(s) end)
local cumweights = {}
local cum = 0.0
for file, wt in pairs(weightmap) do
cum = cum + wt.weight
table.insert(cumweights, { cum = cum, file = file, wt = wt })
end
for idx, ent in ipairs(cumweights) do
taboutf:write(tostring(ent.cum) .. " : " .. ent.file .. "\n")
end
taboutf:close()