1--
2-- path.lua
3-- Path manipulation functions.
4-- Copyright (c) 2002-2014 Jason Perkins and the Premake project
5--
6
7
8--
9-- Appends a file extension to the path. Verifies that the extension
10-- isn't already present, and adjusts quotes as necessary.
11--
12
13	function path.appendExtension(p, ext)
14		-- if the extension is nil or empty, do nothing
15		if not ext or ext == "" then
16			return p
17		end
18
19		-- if the path ends with a quote, pull it off
20		local endquote
21		if p:endswith('"') then
22			p = p:sub(1, -2)
23			endquote = '"'
24		end
25
26		-- add the extension if it isn't there already
27		if not path.hasextension(p, ext) then
28			p = p .. ext
29		end
30
31		-- put the quote back if necessary
32		if endquote then
33			p = p .. endquote
34		end
35
36		return p
37	end
38
39	path.appendextension = path.appendExtension
40
41
42
43--
44-- Retrieve the filename portion of a path, without any extension.
45--
46
47	function path.getbasename(p)
48		local name = path.getname(p)
49		local i = name:findlast(".", true)
50		if (i) then
51			return name:sub(1, i - 1)
52		else
53			return name
54		end
55	end
56
57
58--
59-- Retrieve the directory portion of a path, or an empty string if
60-- the path does not include a directory.
61--
62
63	function path.getdirectory(p)
64		local i = p:findlast("/", true)
65		if (i) then
66			if i > 1 then i = i - 1 end
67			return p:sub(1, i)
68		else
69			return "."
70		end
71	end
72
73
74--
75-- Retrieve the drive letter, if a Windows path.
76--
77
78	function path.getdrive(p)
79		local ch1 = p:sub(1,1)
80		local ch2 = p:sub(2,2)
81		if ch2 == ":" then
82			return ch1
83		end
84	end
85
86
87
88--
89-- Retrieve the file extension.
90--
91
92	function path.getextension(p)
93		p = path.getname(p)
94		local i = p:findlast(".", true)
95		if (i) then
96			return p:sub(i)
97		else
98			return ""
99		end
100	end
101
102
103
104--
105-- Retrieve the filename portion of a path.
106--
107
108	function path.getname(p)
109		local i = p:findlast("[/\\]")
110		if (i) then
111			return p:sub(i + 1)
112		else
113			return p
114		end
115	end
116
117
118
119
120--
121-- Returns true if the filename has a particular extension.
122--
123-- @param fname
124--    The file name to test.
125-- @param extensions
126--    The extension(s) to test. Maybe be a string or table.
127--
128
129	function path.hasextension(fname, extensions)
130		local fext = path.getextension(fname):lower()
131		if type(extensions) == "table" then
132			for _, extension in pairs(extensions) do
133				if fext == extension then
134					return true
135				end
136			end
137			return false
138		else
139			return (fext == extensions)
140		end
141	end
142
143
144--
145-- Returns true if the filename represents various source languages.
146--
147
148	function path.isasmfile(fname)
149		return path.hasextension(fname, { ".s" })
150	end
151
152	function path.iscfile(fname)
153		return path.hasextension(fname, { ".c" })
154			or path.isasmfile(fname)	-- is this really right?
155			or path.isobjcfile(fname)	-- there is code that depends on this behaviour, which would need to change
156	end
157
158	function path.iscppfile(fname)
159		return path.hasextension(fname, { ".cc", ".cpp", ".cxx" })
160			or path.isobjcppfile(fname)	-- is this really right?
161			or path.iscfile(fname)
162	end
163
164	function path.isobjcfile(fname)
165		return path.hasextension(fname, { ".m" })
166	end
167
168	function path.isobjcppfile(fname)
169		return path.hasextension(fname, { ".mm" })
170	end
171
172	function path.iscppheader(fname)
173		return path.hasextension(fname, { ".h", ".hh", ".hpp", ".hxx" })
174	end
175
176
177--
178-- Returns true if the filename represents a native language source file.
179-- These checks are used to prevent passing non-code files to the compiler
180-- in makefiles. It is not foolproof, but it has held up well. I'm open to
181-- better suggestions.
182--
183
184	function path.isnativefile(fname)
185		return path.iscfile(fname)
186			or path.iscppfile(fname)
187			or path.isasmfile(fname)
188			or path.isobjcfile(fname)
189			or path.isobjcppfile(fname)
190	end
191
192
193--
194-- Returns true if the filename represents an OS X framework.
195--
196
197	function path.isframework(fname)
198		return path.hasextension(fname, ".framework")
199	end
200
201
202---
203-- Is this a type of file that can be linked?
204---
205
206	function path.islinkable(fname)
207		return path.hasextension(fname, { ".o", ".obj", ".a", ".lib", ".so" })
208	end
209
210
211
212--
213-- Returns true if the filename represents an object file.
214--
215
216	function path.isobjectfile(fname)
217		return path.hasextension(fname, { ".o", ".obj" })
218	end
219
220
221--
222-- Returns true if the filename represents a Windows resource file. This check
223-- is used to prevent passing non-resources to the compiler in makefiles.
224--
225
226	function path.isresourcefile(fname)
227		return path.hasextension(fname, ".rc")
228	end
229
230--
231-- Returns true if the filename represents a Windows idl file.
232--
233
234	function path.isidlfile(fname)
235		return path.hasextension(fname, ".idl")
236	end
237
238
239--
240-- Takes a path which is relative to one location and makes it relative
241-- to another location instead.
242--
243
244	function path.rebase(p, oldbase, newbase)
245		p = path.getabsolute(path.join(oldbase, p))
246		p = path.getrelative(newbase, p)
247		return p
248	end
249
250
251
252--
253-- Replace the file extension.
254--
255
256	function path.replaceextension(p, newext)
257		local ext = path.getextension(p)
258
259		if not ext then
260			return p
261		end
262
263		if #newext > 0 and not newext:findlast(".", true) then
264			newext = "."..newext
265		end
266
267		return p:match("^(.*)"..ext.."$")..newext
268	end
269
270--
271-- Get the default seperator for path.translate
272--
273
274	function path.getDefaultSeparator()
275		if os.istarget('windows') then
276			return '\\'
277		else
278			return '/'
279		end
280	end
281