| |
1 |
| |
2 --@module path |
| |
3 local path={} |
| |
4 |
| |
5 local tuple=require("tuple") |
| |
6 local lfs=require("lfs") |
| |
7 local err=require("err") |
| |
8 local config=require("config") |
| |
9 |
| |
10 local sep=config.dirsep |
| |
11 |
| |
12 function path.join(p, f) |
| |
13 if p=="" then |
| |
14 return f |
| |
15 else |
| |
16 return p..sep..f |
| |
17 end |
| |
18 end |
| |
19 |
| |
20 function path.dirbasename(p) |
| |
21 local d, b = string.match(p, |
| |
22 "^(.*)"..sep.."+([^"..sep.."]+)"..sep.."*$") |
| |
23 if not b then |
| |
24 return "", p |
| |
25 else |
| |
26 return d, b |
| |
27 end |
| |
28 end |
| |
29 |
| |
30 function path.dirname(p) |
| |
31 return tuple.fst(dirbasename(p)) |
| |
32 end |
| |
33 |
| |
34 function path.dirname_slash(p) |
| |
35 local dn=dirname(p) |
| |
36 if dn=="" then |
| |
37 return dn |
| |
38 else |
| |
39 return dn..sep |
| |
40 end |
| |
41 end |
| |
42 |
| |
43 function path.basename(p) |
| |
44 return tuple.snd(dirbasename(p)) |
| |
45 end |
| |
46 |
| |
47 function path.rmext(p) |
| |
48 return string.gsub(p, "%.[^.]*$", "") |
| |
49 end |
| |
50 |
| |
51 -- would rather do this as an iterator, but can't |
| |
52 -- coroutine.yield from gsub handler |
| |
53 function path.split(p) |
| |
54 local t={} |
| |
55 local head="" |
| |
56 local s, p2 = string.match(p, "^("..sep.."+)(.*)$") |
| |
57 if s then |
| |
58 table.insert(t, "/.") -- root |
| |
59 p=p2 |
| |
60 end |
| |
61 string.gsub(p, "([^"..sep.."]+)", --..sep.."+", |
| |
62 function(d) table.insert(t, d); end) |
| |
63 return t |
| |
64 end |
| |
65 |
| |
66 --[[ |
| |
67 function path.parts(p) |
| |
68 local s={i=1, t=split(p)} |
| |
69 local function g(s) |
| |
70 local v=s.t[s.i] |
| |
71 s.i=s.i+1 |
| |
72 return v |
| |
73 end |
| |
74 return g, s |
| |
75 end |
| |
76 |
| |
77 function path.makepath(p, head) |
| |
78 head=head or "" |
| |
79 for d in parts(p) do |
| |
80 head=head..d |
| |
81 local a=lfs.attributes(head) |
| |
82 if not a then |
| |
83 local success, e = lfs.mkdir(head) |
| |
84 if not success then |
| |
85 err.file(head, e) |
| |
86 end |
| |
87 elseif a.mode~="directory" then |
| |
88 err.file(head, "not a directory") |
| |
89 end |
| |
90 head=head..sep |
| |
91 end |
| |
92 end |
| |
93 ]] |
| |
94 |
| |
95 function path.simplify(p) |
| |
96 local capts={} |
| |
97 local start=string.match(p, "^(/)") |
| |
98 string.gsub(p, "([^/]+)", |
| |
99 function(e) |
| |
100 if e==".." and #capts > 1 then |
| |
101 capts[#capts]=nil |
| |
102 elseif e~="." then |
| |
103 table.insert(capts, e) |
| |
104 end |
| |
105 end) |
| |
106 return (start or "")..table.concat(capts, "/") |
| |
107 end |
| |
108 |
| |
109 function path.to_root(p) |
| |
110 return string.rep("../",#(path.split(p))-1) |
| |
111 end |
| |
112 |
| |
113 return path |