summaryrefslogtreecommitdiff
path: root/lib/ldirlib.c
blob: 8e68f0b1334868b77ce457c7c525b3571a166e59 (plain)
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>

#define ldirlib_c

#define LUA_DIRLIBNAME "dir"

#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);
    char * d_path, * p;
    DIR **d;

    /* create a userdatum to store a DIR address */
    p = (char *) lua_newuserdata(L, sizeof(DIR *) + strlen(path) + 1);
    d = (DIR **) p;
    d_path = p + sizeof(DIR *);

    strcpy(d_path, path);

    /* 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) {
    char * p = (char *) lua_touserdata(L, lua_upvalueindex(1));
    DIR * d = *(DIR **) p;
    char * path = p + sizeof(DIR *);
    char * fullpath;
    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);
	fullpath = (char *) malloc(strlen(path) + strlen(entry->d_name) + 2);
	sprintf(fullpath, "%s/%s", path, entry->d_name);
#ifdef _WIN32
	_stat(fullpath, &file_stat);
#else
	stat(fullpath, &file_stat);
#endif
	free(fullpath);
	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");

    lua_pop(L, 1);

    return 0;
}