1 // Copyright 2011 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "utils/fs/lua_module.hpp"
40 #include <lutok/operations.hpp>
41 #include <lutok/state.ipp>
43 #include "utils/format/macros.hpp"
44 #include "utils/fs/operations.hpp"
45 #include "utils/fs/path.hpp"
46 #include "utils/sanity.hpp"
48 namespace fs
= utils::fs
;
54 /// Lua binding for fs::path::basename.
56 /// \pre stack(-1) The input path.
57 /// \post stack(-1) The basename of the input path.
59 /// \param state The Lua state.
61 /// \return The number of result values, i.e. 1.
63 lua_fs_basename(lutok::state
& state
)
65 if (!state
.is_string())
66 throw std::runtime_error("Need a string parameter");
67 const fs::path
path(state
.to_string());
69 state
.push_string(path
.leaf_name().c_str());
74 /// Lua binding for fs::path::dirname.
76 /// \pre stack(-1) The input path.
77 /// \post stack(-1) The directory part of the input path.
79 /// \param state The Lua state.
81 /// \return The number of result values, i.e. 1.
83 lua_fs_dirname(lutok::state
& state
)
85 if (!state
.is_string())
86 throw std::runtime_error("Need a string parameter");
87 const fs::path
path(state
.to_string());
89 state
.push_string(path
.branch_path().c_str());
94 /// Lua binding for fs::path::exists.
96 /// \pre stack(-1) The input path.
97 /// \post stack(-1) Whether the input path exists or not.
99 /// \param state The Lua state.
101 /// \return The number of result values, i.e. 1.
103 lua_fs_exists(lutok::state
& state
)
105 if (!state
.is_string())
106 throw std::runtime_error("Need a string parameter");
107 const fs::path
path(state
.to_string());
109 state
.push_boolean(fs::exists(path
));
114 /// Lua binding for the files iterator.
116 /// This function takes an open directory from the closure of the iterator and
117 /// returns the next entry. See lua_fs_files() for the iterator generator
120 /// \pre upvalue(1) The userdata containing an open DIR* object.
122 /// \param state The lua state.
124 /// \return The number of result values, i.e. 0 if there are no more entries or
125 /// 1 if an entry has been read.
127 files_iterator(lutok::state
& state
)
129 DIR** dirp
= state
.to_userdata
< DIR* >(state
.upvalue_index(1));
130 const struct dirent
* entry
= ::readdir(*dirp
);
134 state
.push_string(entry
->d_name
);
140 /// Lua binding for the destruction of the files iterator.
142 /// This function takes an open directory and closes it. See lua_fs_files() for
143 /// the iterator generator function.
145 /// \pre stack(-1) The userdata containing an open DIR* object.
146 /// \post The DIR* object is closed.
148 /// \param state The lua state.
150 /// \return The number of result values, i.e. 0.
152 files_gc(lutok::state
& state
)
154 PRE(state
.is_userdata());
156 DIR** dirp
= state
.to_userdata
< DIR* >();
157 // For some reason, this may be called more than once. I don't know why
158 // this happens, but we must protect against it.
168 /// Lua binding to create an iterator to scan the contents of a directory.
170 /// \pre stack(-1) The input path.
171 /// \post stack(-1) The iterator function.
173 /// \param state The Lua state.
175 /// \return The number of result values, i.e. 1.
177 lua_fs_files(lutok::state
& state
)
179 if (!state
.is_string())
180 throw std::runtime_error("Need a string parameter");
181 const fs::path
path(state
.to_string());
183 DIR** dirp
= state
.new_userdata
< DIR* >();
186 state
.push_string("__gc");
187 state
.push_cxx_function(files_gc
);
190 state
.set_metatable();
192 *dirp
= ::opendir(path
.c_str());
194 const int original_errno
= errno
;
195 throw std::runtime_error(F("Failed to open directory: %s") %
196 std::strerror(original_errno
));
199 state
.push_cxx_closure(files_iterator
, 1);
205 /// Lua binding for fs::path::is_absolute.
207 /// \pre stack(-1) The input path.
208 /// \post stack(-1) Whether the input path is absolute or not.
210 /// \param state The Lua state.
212 /// \return The number of result values, i.e. 1.
214 lua_fs_is_absolute(lutok::state
& state
)
216 if (!state
.is_string())
217 throw std::runtime_error("Need a string parameter");
218 const fs::path
path(state
.to_string());
220 state
.push_boolean(path
.is_absolute());
225 /// Lua binding for fs::path::operator/.
227 /// \pre stack(-2) The first input path.
228 /// \pre stack(-1) The second input path.
229 /// \post stack(-1) The concatenation of the two paths.
231 /// \param state The Lua state.
233 /// \return The number of result values, i.e. 1.
235 lua_fs_join(lutok::state
& state
)
237 if (!state
.is_string(-2))
238 throw std::runtime_error("Need a string parameter");
239 const fs::path
path1(state
.to_string(-2));
241 if (!state
.is_string(-1))
242 throw std::runtime_error("Need a string parameter");
243 const fs::path
path2(state
.to_string(-1));
245 state
.push_string((path1
/ path2
).c_str());
250 } // anonymous namespace
253 /// Creates a Lua 'fs' module.
255 /// \post The global 'fs' symbol is set to a table that contains functions to a
256 /// variety of utilites from the fs C++ module.
258 /// \param s The Lua state.
260 fs::open_fs(lutok::state
& s
)
262 std::map
< std::string
, lutok::cxx_function
> members
;
263 members
["basename"] = lua_fs_basename
;
264 members
["dirname"] = lua_fs_dirname
;
265 members
["exists"] = lua_fs_exists
;
266 members
["files"] = lua_fs_files
;
267 members
["is_absolute"] = lua_fs_is_absolute
;
268 members
["join"] = lua_fs_join
;
269 lutok::create_module(s
, "fs", members
);