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
|
--[[
Copyright (c) 2012-2016 Kaarle Ritvanen
See LICENSE file for license details
--]]
--- @module aconf.model
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
--- joins a number of already escaped path components into a single
--- path.
-- @function path.rawjoin
-- @tparam string p1 path component
-- @tparam ?string p2 path component
-- @tparam ?string ... path component
-- @treturn string path
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
--- appends a number of additional components to a path. The appended
-- components are escaped first.
-- @function path.join
-- @tparam string parent path
-- @tparam ?string ... path component
-- @treturn string path
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
|