summaryrefslogtreecommitdiffstats
path: root/aconf/path.lua
diff options
context:
space:
mode:
Diffstat (limited to 'aconf/path.lua')
-rw-r--r--aconf/path.lua121
1 files changed, 121 insertions, 0 deletions
diff --git a/aconf/path.lua b/aconf/path.lua
new file mode 100644
index 0000000..4e289f5
--- /dev/null
+++ b/aconf/path.lua
@@ -0,0 +1,121 @@
+--[[
+Copyright (c) 2012-2015 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+local M = {}
+
+local map = require('aconf.util').map
+
+M.up = {symbol='..'}
+M.wildcard = {symbol='*'}
+local special = {['..']=M.up, ['*']=M.wildcard}
+
+
+function M.is_absolute(path) return path:sub(1, 1) == '/' end
+
+
+function M.escape(comp)
+ if type(comp) == 'table' then
+ assert(comp.symbol)
+ return comp.symbol
+ end
+ if type(comp) == 'number' then return tostring(comp) end
+ local res = comp:gsub('([\\/])', '\\%1')
+ return (special[res] or tonumber(res)) and '\\'..res or res
+end
+
+
+function M.rawjoin(p1, p2, ...)
+ if not p2 then return p1 end
+ if not M.is_absolute(p2) then p2 = '/'..p2 end
+ return M.rawjoin((p1 == '/' and '' or p1)..p2, ...)
+end
+
+function M.join(parent, ...)
+ local args = map(function(c) return M.escape(c) end, {...})
+ if parent > '' then table.insert(args, 1, parent) end
+ return M.rawjoin(table.unpack(args))
+end
+
+
+function M.split(path)
+ local res = {}
+ local comp = ''
+ local escaped
+
+ local function merge(s)
+ if s > '' then
+ table.insert(res, not escaped and (special[s] or tonumber(s)) or s)
+ end
+ end
+
+ while true do
+ local prefix, sep, suffix = path:match('([^\\/]*)([\\/])(.*)')
+ if not prefix then
+ merge(comp..path)
+ return res
+ end
+
+ comp = comp..prefix
+ if sep == '\\' then
+ comp = comp..suffix:sub(1, 1)
+ escaped = true
+ path = suffix:sub(2, -1)
+ else
+ merge(comp)
+ comp = ''
+ escaped = false
+ path = suffix
+ end
+ end
+end
+
+
+function M.is_unique(path)
+ for _, comp in ipairs(M.split(path)) do
+ if comp == M.wildcard then return false end
+ end
+ return true
+end
+
+function M.is_subordinate(p1, p2)
+ p1 = M.split(p1)
+ for i, comp in ipairs(M.split(p2)) do
+ if p1[i] ~= comp then return false end
+ end
+ return true
+end
+
+
+function M.to_absolute(path, base)
+ if not M.is_absolute(path) then
+ path = base..(base ~= '/' and '/' or '')..path
+ end
+ local comps = M.split(path)
+ local i = 1
+ while i <= #comps do
+ if comps[i] == M.up then
+ if i == 1 then error('Invalid path: '..path) end
+ table.remove(comps, i - 1)
+ table.remove(comps, i - 1)
+ i = i - 1
+ else i = i + 1 end
+ end
+ return M.join('/', table.unpack(comps))
+end
+
+
+function M.parent(path)
+ local comps = M.split(path)
+ table.remove(comps)
+ return M.join('/', table.unpack(comps))
+end
+
+function M.name(path)
+ local comps = M.split(path)
+ return comps[#comps]
+end
+
+
+return M