summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/clua.h
blob: f5a0050ccaefd2b082757d00ba1548a19016b343 (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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
 *  File:       clua.h
 *  Created by: dshaligram on Wed Aug 2 12:54:15 2006 UTC
 *
 *  Modified for Crawl Reference by $Author$ on $Date$
 */


#ifndef __CLUA_H__
#define __CLUA_H__

#include "AppHdr.h"

extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}

#include <cstdio>
#include <cstdarg>
#include <string>
#include <map>
#include <set>

#include "libutil.h"
#include "externs.h"

#ifndef CLUA_MAX_MEMORY_USE
#define CLUA_MAX_MEMORY_USE (6 * 1024)
#endif

class CLua;

class lua_stack_cleaner
{
public:
    lua_stack_cleaner(lua_State *_ls) : ls(_ls), top(lua_gettop(_ls)) { }
    ~lua_stack_cleaner() { lua_settop(ls, top); }
private:
    lua_State *ls;
    int top;
};

class lua_call_throttle
{
public:
    lua_call_throttle(CLua *handle);
    ~lua_call_throttle();

    static CLua *find_clua(lua_State *ls);

private:
    CLua *lua;

    typedef std::map<lua_State *, CLua *> lua_clua_map;
    static lua_clua_map lua_map;
};

class CLua
{
public:
    CLua(bool managed = true);
    ~CLua();

    lua_State *state();

    operator lua_State * ()
    {
        return state();
    }

    void save(const char *filename);

    void setglobal(const char *name);
    void getglobal(const char *name);

    // Assigns the value on top of the stack to a unique name in the registry
    // and returns the name.
    std::string setuniqregistry();

    void setregistry(const char *name);
    void getregistry(const char *name);

    int loadbuffer(const char *buf, size_t size, const char *context);
    int loadstring(const char *str, const char *context);
    int execstring(const char *str, const char *context = "init.txt",
                   int nresults = 0);
    int execfile(const char *filename, bool trusted = false,
                 bool die_on_fail = false);

    bool callbooleanfn(bool defval, const char *fn, const char *params, ...);
    bool callfn(const char *fn, int nargs, int nret = 1);
    bool callfn(const char *fn, const char *params, ...);
    void fnreturns(const char *params, ...);
    bool runhook(const char *hook, const char *params, ...);

    static int file_write(lua_State *ls);
    static int loadfile(lua_State *ls, const char *file,
                        bool trusted = false, bool die_on_fail = false);
    static bool is_path_safe(std::string file, bool trusted = false);

    static bool is_managed_vm(lua_State *ls);

public:
    std::string error;

    // If managed_vm is set, we have to take steps to control badly-behaved
    // scripts.
    bool managed_vm;
    bool shutting_down;
    int throttle_unit_lines;
    int throttle_sleep_ms;
    int throttle_sleep_start, throttle_sleep_end;
    int n_throttle_sleeps;
    int mixed_call_depth;
    int lua_call_depth;
    int max_mixed_call_depth;
    int max_lua_call_depth;

    long memory_used;

    static const int MAX_THROTTLE_SLEEPS = 100;

private:
    lua_State *_state;
    typedef std::set<std::string> sfset;
    sfset sourced_files;
    unsigned long uniqindex;

private:
    void init_lua();
    void set_error(int err, lua_State *ls = NULL);
    void load_cmacro();
    void load_chooks();
    void init_throttle();

    void vfnreturns(const char *par, va_list va);

    bool proc_returns(const char *par) const;

    bool calltopfn(lua_State *ls, const char *format, va_list args,
                   int retc = -1, va_list *fnr = NULL);

    int push_args(lua_State *ls, const char *format, va_list args,
                    va_list *cpto = NULL);
    int return_count(lua_State *ls, const char *format);

    struct CLuaSave
    {
        const char *filename;
        FILE *handle;

        FILE *get_file();
    };

    friend class lua_call_throttle;
};

class lua_text_pattern : public base_pattern
{
public:
    lua_text_pattern(const std::string &pattern);
    ~lua_text_pattern();

    bool valid() const;
    bool matches(const std::string &s) const;

    static bool is_lua_pattern(const std::string &s);

private:
    bool        translated;
    bool        isvalid;
    std::string pattern;
    std::string lua_fn_name;

    static unsigned long lfndx;

    bool translate() const;
    void pre_pattern(std::string &pat, std::string &fn) const;
    void post_pattern(std::string &pat, std::string &fn) const;

    static std::string new_fn_name();
};

// Defined in acr.cc
extern CLua clua;

void lua_set_exclusive_item(const item_def *item = NULL);

#define LUAWRAP(name, wrapexpr) \
    static int name(lua_State *ls) \
    {   \
        wrapexpr; \
        return (0); \
    }

#define PLUARET(type, val) \
        lua_push##type(ls, val); \
        return (1);

#define LUARET1(name, type, val) \
    static int name(lua_State *ls) \
    { \
        lua_push##type(ls, val); \
        return (1); \
    }

#define LUARET2(name, type, val1, val2)  \
    static int name(lua_State *ls) \
    { \
        lua_push##type(ls, val1); \
        lua_push##type(ls, val2); \
        return (2); \
    }

template <class T>
inline static T *util_get_userdata(lua_State *ls, int ndx)
{
    return (lua_islightuserdata(ls, ndx))?
            static_cast<T *>( lua_touserdata(ls, ndx) )
          : NULL;
}

template <class T>
inline static T *clua_get_userdata(lua_State *ls, const char *mt)
{
    return static_cast<T*>( luaL_checkudata( ls, 1, mt ) );
}

std::string quote_lua_string(const std::string &s);

class map_def;
class dgn_event;
void clua_push_map(lua_State *ls, map_def *map);
void clua_push_dgn_event(lua_State *ls, const dgn_event *devent);

template <class T> T *clua_new_userdata(
        lua_State *ls, const char *mt)
{
    void *udata = lua_newuserdata( ls, sizeof(T) );
    luaL_getmetatable(ls, mt);
    lua_setmetatable(ls, -2);
    return static_cast<T*>( udata );
}

void push_monster(lua_State *ls, monsters *mons);

#define MAP_METATABLE "dgn.mtmap"
#define DEVENT_METATABLE "dgn.devent"
#define MAPMARK_METATABLE "dgn.mapmark"

#endif