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
|
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#define ldirlib_c
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/* forward declaration for the iterator function */
static int dir_iter (lua_State *L);
static int l_dir (lua_State *L) {
const char *path = luaL_checkstring(L, 1);
/* create a userdatum to store a DIR address */
DIR **d = (DIR **)lua_newuserdata(L, sizeof(DIR *));
/* set its metatable */
luaL_getmetatable(L, "LuaBook.dir");
lua_setmetatable(L, -2);
/* try to open the given directory */
*d = opendir(path);
if (*d == NULL) /* error opening the directory? */
luaL_error(L, "cannot open %s: %s", path,
strerror(errno));
/* creates and returns the iterator function
(its sole upvalue, the directory userdatum,
is already on the stack top */
lua_pushcclosure(L, dir_iter, 1);
return 1;
}
static int dir_iter (lua_State *L) {
DIR *d = *(DIR **)lua_touserdata(L, lua_upvalueindex(1));
struct dirent *entry;
#ifdef _WIN32
struct _stat file_stat;
#else
struct stat file_stat;
#endif
if ((entry = readdir(d)) != NULL) {
lua_newtable(L);
lua_pushstring(L, "name");
lua_pushstring(L, entry->d_name);
lua_settable(L, -3);
#ifdef _WIN32
_stat(entry->d_name, &file_stat);
#else
stat(entry->d_name, &file_stat);
#endif
lua_pushstring(L, "type");
lua_pushnumber(L, (S_IFREG & file_stat.st_mode) ? 2 : ((S_IFDIR & file_stat.st_mode) ? 1 : 0));
lua_settable(L, -3);
return 1;
}
else return 0; /* no more values to return */
}
static int dir_gc (lua_State *L) {
DIR *d = *(DIR **)lua_touserdata(L, 1);
if (d) closedir(d);
return 0;
}
static const luaL_reg dirlib[] = {
{NULL, NULL}
};
int luaopen_dir (lua_State *L) {
luaL_openlib(L, LUA_DIRLIBNAME, dirlib, 0);
luaL_newmetatable(L, "LuaBook.dir");
/* set its __gc field */
lua_pushstring(L, "__gc");
lua_pushcfunction(L, dir_gc);
lua_settable(L, -3);
/* register the `dir' function */
lua_pushcfunction(L, l_dir);
lua_setglobal(L, "dir");
lua_pushnumber(L, 1);
lua_setglobal(L, "FLAG_DIR");
lua_pushnumber(L, 2);
lua_setglobal(L, "FLAG_FILE");
return 0;
}
|