winamp/Src/external_dependencies/openmpt-trunk/include/premake/src/base/detoken.lua

203 lines
5.3 KiB
Lua

--
-- detoken.lua
--
-- Expands tokens.
--
-- Copyright (c) 2011-2014 Jason Perkins and the Premake project
--
local p = premake
p.detoken = {}
local detoken = p.detoken
--
-- Expand tokens in a value.
--
-- @param value
-- The value containing the tokens to be expanded.
-- @param environ
-- An execution environment for any token expansion. This is a list of
-- key-value pairs that will be inserted as global variables into the
-- token expansion runtime environment.
-- @param field
-- The definition of the field which stores the value.
-- @param basedir
-- If provided, path tokens encountered in non-path fields (where
-- field.paths is set to false) will be made relative to this location.
-- @return
-- The value with any contained tokens expanded.
--
function detoken.expand(value, environ, field, basedir)
function expandtoken(token, e, f)
-- fetch the path variable from the action, if needed
local varMap = {}
if f.pathVars or e.overridePathVars then
local action = p.action.current()
if action then
varMap = action.pathVars or {}
end
end
-- fetch the pathVars from the enviroment.
local envMap = e.pathVars or {}
-- enable access to the global environment
setmetatable(e, {__index = _G})
local isAbs = false
local err
local result
local success
-- if the token starts with a !, don't try making it relative.
local dontMakeRelative = token:startswith('!')
if dontMakeRelative then
token = token:sub(2, -1)
end
-- If this token is in my path variable mapping tables, replace the
-- value with the one from the map. This needs to go here because
-- I don't want to make the result relative, but I don't want the
-- absolute path handling below.
local mapped = envMap[token] or varMap[token]
if mapped then
err = nil
result = mapped
if type(result) == "function" then
success, result = pcall(result, e)
if not success then
return nil, result
end
end
if (type(result) == "table") then
isAbs = result.absolute
result = result.token
else
isAbs = path.isabsolute(result)
end
else
-- convert the token into a function to execute
local func
func, err = load("return " .. token, nil, 't', e)
if not func then
return nil, "load error: " .. err
end
-- run it and get the result
success, result = pcall(func)
if not success then
err = result
result = nil
else
err = nil
result = result or ""
end
if result ~= nil then
-- ensure we got a string.
result = tostring(result)
-- If the result is an absolute path, and it is being inserted into
-- a NON-path value, I need to make it relative to the project that
-- will contain it. Otherwise I ended up with an absolute path in
-- the generated project, and it can no longer be moved around.
if path.hasdeferredjoin(result) then
result = path.resolvedeferredjoin(result)
end
isAbs = path.isabsolute(result)
if isAbs and not f.paths and basedir and not dontMakeRelative then
result = path.getrelative(basedir, result)
end
end
end
-- If the result is an absolute path, and it is being inserted into
-- a path value, place a special marker at the start of it. After
-- all results have been processed, I can look for these markers to
-- find the last absolute path expanded.
--
-- Example: the value "/home/user/myprj/%{cfg.objdir}" expands to:
-- "/home/user/myprj//home/user/myprj/obj/Debug".
--
-- By inserting a marker this becomes:
-- "/home/user/myprj/[\0]/home/user/myprj/obj/Debug".
--
-- I can now trim everything before the marker to get the right
-- result, which should always be the last absolute path specified:
-- "/home/user/myprj/obj/Debug"
if result ~= nil and isAbs and f.paths then
result = "\0" .. result
end
return result, err
end
function expandvalue(value, e, f)
if type(value) ~= "string" then
return value
end
local count
repeat
value, count = value:gsub("%%{(.-)}", function(token)
local result, err = expandtoken(token:gsub("\\", "\\\\"), e, f)
if err then
error(err .. " in token: " .. token, 0)
end
if not result then
error("Token returned nil, it may not exist: " .. token, 0)
end
return result
end)
until count == 0
-- if a path, look for a split out embedded absolute paths
if f.paths then
local i, j
repeat
i, j = value:find("\0")
if i then
value = value:sub(i + 1)
end
until not i
end
return value
end
local expand_cache = {}
function recurse(value, e, f)
if type(value) == "table" then
local res_table = {}
for k, v in pairs(value) do
if tonumber(k) ~= nil then
res_table[k] = recurse(v, e, f)
else
local nk = recurse(k, e, f)
res_table[nk] = recurse(v, e, f)
end
end
return res_table
else
local res = expand_cache[value]
if res == nil then
if type(value) == "string" and path.hasdeferredjoin(value) then
value = path.resolvedeferredjoin(value)
end
res = expandvalue(value, e, f)
expand_cache[value] = res
end
return res
end
end
return recurse(value, environ, field or {})
end