Improve the process for GNU tools
[minix3.git] / external / bsd / kyua-cli / dist / utils / fs / lua_module.cpp
blob9162159665074712220e8df9a640819f5fce41d0
1 // Copyright 2011 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
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"
31 extern "C" {
32 #include <dirent.h>
35 #include <cerrno>
36 #include <cstring>
37 #include <stdexcept>
38 #include <string>
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;
51 namespace {
54 /// Lua binding for fs::path::basename.
55 ///
56 /// \pre stack(-1) The input path.
57 /// \post stack(-1) The basename of the input path.
58 ///
59 /// \param state The Lua state.
60 ///
61 /// \return The number of result values, i.e. 1.
62 static int
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());
70 return 1;
74 /// Lua binding for fs::path::dirname.
75 ///
76 /// \pre stack(-1) The input path.
77 /// \post stack(-1) The directory part of the input path.
78 ///
79 /// \param state The Lua state.
80 ///
81 /// \return The number of result values, i.e. 1.
82 static int
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());
90 return 1;
94 /// Lua binding for fs::path::exists.
95 ///
96 /// \pre stack(-1) The input path.
97 /// \post stack(-1) Whether the input path exists or not.
98 ///
99 /// \param state The Lua state.
101 /// \return The number of result values, i.e. 1.
102 static int
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));
110 return 1;
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
118 /// function.
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.
126 static int
127 files_iterator(lutok::state& state)
129 DIR** dirp = state.to_userdata< DIR* >(state.upvalue_index(1));
130 const struct dirent* entry = ::readdir(*dirp);
131 if (entry == NULL)
132 return 0;
133 else {
134 state.push_string(entry->d_name);
135 return 1;
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.
151 static int
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.
159 if (*dirp != NULL) {
160 ::closedir(*dirp);
161 *dirp = NULL;
164 return 0;
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.
176 static int
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* >();
185 state.new_table();
186 state.push_string("__gc");
187 state.push_cxx_function(files_gc);
188 state.set_table();
190 state.set_metatable();
192 *dirp = ::opendir(path.c_str());
193 if (*dirp == NULL) {
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);
201 return 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.
213 static int
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());
221 return 1;
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.
234 static int
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());
246 return 1;
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.
259 void
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);