summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/l_file.cc
blob: fae724fcfd4e9323a6300f760c8c939d0691b89f (plain) (blame)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include "AppHdr.h"

#include "clua.h"
#include "cluautil.h"
#include "dlua.h"
#include "l_libs.h"
#include "files.h"

#include "tags.h"

///////////////////////////////////////////////////////////
// User-accessible file operations

static const struct luaL_reg file_clib[] =
{
    { "write", CLua::file_write },
    { NULL, NULL },
};

void cluaopen_file(lua_State *ls)
{
    luaL_openlib(ls, "file", file_clib, 0);
}

///////////////////////////////////////////////////////////
// Non-user-accessible file operations

static int file_marshall(lua_State *ls)
{
    if (lua_gettop(ls) != 2)
        luaL_error(ls, "Need two arguments: tag header and value");
    writer &th(*static_cast<writer*>( lua_touserdata(ls, 1) ));
    if (lua_isnumber(ls, 2))
        marshallLong(th, luaL_checklong(ls, 2));
    else if (lua_isboolean(ls, 2))
        marshallByte(th, lua_toboolean(ls, 2));
    else if (lua_isstring(ls, 2))
        marshallString(th, lua_tostring(ls, 2));
    else if (lua_isfunction(ls, 2))
    {
        dlua_chunk chunk(ls);
        marshallString(th, chunk.compiled_chunk());
    }
    return (0);
}

static int file_unmarshall_boolean(lua_State *ls)
{
    if (lua_gettop(ls) != 1)
        luaL_error(ls, "Need reader as one argument");
    reader &th(*static_cast<reader*>( lua_touserdata(ls, 1) ));
    lua_pushboolean(ls, unmarshallByte(th));
    return (1);
}

static int file_unmarshall_number(lua_State *ls)
{
    if (lua_gettop(ls) != 1)
        luaL_error(ls, "Need reader as one argument");
    reader &th(*static_cast<reader*>( lua_touserdata(ls, 1) ));
    lua_pushnumber(ls, unmarshallLong(th));
    return (1);
}

static int file_unmarshall_string(lua_State *ls)
{
    if (lua_gettop(ls) != 1)
        luaL_error(ls, "Need reader as one argument");
    reader &th(*static_cast<reader*>( lua_touserdata(ls, 1) ));
    lua_pushstring(ls, unmarshallString(th).c_str());
    return (1);
}

static int file_unmarshall_fn(lua_State *ls)
{
    if (lua_gettop(ls) != 1)
        luaL_error(ls, "Need reader as one argument");
    reader &th(*static_cast<reader*>( lua_touserdata(ls, 1) ));
    const std::string s(unmarshallString(th, LUA_CHUNK_MAX_SIZE));
    dlua_chunk chunk = dlua_chunk::precompiled(s);
    if (chunk.load(dlua))
        lua_pushnil(ls);
    return (1);
}

enum lua_persist_type
{
    LPT_NONE,
    LPT_NUMBER,
    LPT_STRING,
    LPT_FUNCTION,
    LPT_NIL,
    LPT_BOOLEAN
};

static int file_marshall_meta(lua_State *ls)
{
    if (lua_gettop(ls) != 2)
        luaL_error(ls, "Need two arguments: tag header and value");

    writer &th(*static_cast<writer*>( lua_touserdata(ls, 1) ));

    lua_persist_type ptype = LPT_NONE;
    if (lua_isnumber(ls, 2))
        ptype = LPT_NUMBER;
    else if (lua_isboolean(ls, 2))
        ptype = LPT_BOOLEAN;
    else if (lua_isstring(ls, 2))
        ptype = LPT_STRING;
    else if (lua_isfunction(ls, 2))
        ptype = LPT_FUNCTION;
    else if (lua_isnil(ls, 2))
        ptype = LPT_NIL;
    else
        luaL_error(ls,
                   make_stringf("Cannot marshall %s",
                                lua_typename(ls, lua_type(ls, 2))).c_str());
    marshallByte(th, ptype);
    if (ptype != LPT_NIL)
        file_marshall(ls);
    return (0);
}

static int file_unmarshall_meta(lua_State *ls)
{
    reader &th(*static_cast<reader*>( lua_touserdata(ls, 1) ));
    const lua_persist_type ptype =
    static_cast<lua_persist_type>(unmarshallByte(th));
    switch (ptype)
    {
        case LPT_BOOLEAN:
            return file_unmarshall_boolean(ls);
        case LPT_NUMBER:
            return file_unmarshall_number(ls);
        case LPT_STRING:
            return file_unmarshall_string(ls);
        case LPT_FUNCTION:
            return file_unmarshall_fn(ls);
        case LPT_NIL:
            lua_pushnil(ls);
            return (1);
        default:
            luaL_error(ls, "Unexpected type signature.");
    }
    // Never get here.
    return (0);
}

// Returns a Lua table of filenames in the named directory. The file names
// returned are unqualified. The directory must be a relative path, and will
// be resolved to an absolute path if necessary using datafile_path.
LUAFN(_file_datadir_files)
{
    const std::string rawdir(luaL_checkstring(ls, 1));
    // A filename suffix to match (such as ".des"). If empty, files
    // will be unfiltered.
    const std::string ext_filter(lua_isnoneornil(ls, 2) ? "" :
                                 luaL_checkstring(ls, 2));
    const std::string datadir(
        datafile_path(rawdir, false, false, dir_exists));

    if (datadir.empty())
        luaL_error(ls, "Cannot find data directory: '%s'", rawdir.c_str());

    const std::vector<std::string> files =
        ext_filter.empty() ? get_dir_files(datadir) :
        get_dir_files_ext(datadir, ext_filter);
    return clua_stringtable(ls, files);
}

LUAFN(_file_writefile)
{
    const std::string fname(luaL_checkstring(ls, 1));
    FILE *f = fopen(fname.c_str(), "w");
    if (f)
    {
        fprintf(f, "%s", luaL_checkstring(ls, 2));
        fclose(f);
        lua_pushboolean(ls, true);
    }
    else
    {
        lua_pushboolean(ls, false);
    }
    return (1);
}

static const struct luaL_reg file_dlib[] =
{
    { "marshall",   file_marshall },
    { "marshall_meta", file_marshall_meta },
    { "unmarshall_meta", file_unmarshall_meta },
    { "unmarshall_number", file_unmarshall_number },
    { "unmarshall_string", file_unmarshall_string },
    { "unmarshall_fn", file_unmarshall_fn },
    { "writefile", _file_writefile },
    { "datadir_files", _file_datadir_files },
    { NULL, NULL }
};

void dluaopen_file(lua_State *ls)
{
    luaL_openlib(ls, "file", file_dlib, 0);
}