-
Notifications
You must be signed in to change notification settings - Fork 2
/
BENEFITS-C
392 lines (308 loc) · 16.6 KB
/
BENEFITS-C
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
BENEFITS-C
==========
What do I get when I #include "fiveq.h" and link against fiveq.a?
-----------------------------------------------------------------
Fiveq backports most of Lua 5.2's C API to Lua 5.1, and vice-versa. For
missing features, see the accompanying file LIMITATIONS.
Here is the complete list of interfaces that are provided to Lua 5.1:
* lua_pushglobaltable
* lua_absindex
* lua_copy
like lua_replace but don't pop element from top
* lua_tonumberx(L, idx, bool *isnum)
returns stack[idx] converted to lua_Number, or 0 if non-convertible
if isnum is non-NULL, assigns whether stack[idx] was convertible
* lua_tointegerx(L, idx, bool *isnum)
returns stack[idx] converted (and if needed, truncated in undefined
way) to the signed type lua_Integer, or 0 if non-convertible
if isnum is non-NULL, assigns whether stack[idx] was convertible
* typedef lua_Unsigned
must be >= 32 bits, by default is unsigned int or unsigned long
* lua_tounsigned
* lua_tounsignedx(L, idx, bool *isnum)
returns stack[idx] converted (and if needed, truncated in undefined
way) to lua_Unsigned, or 0 if non-convertible
if outside the range of representable values, is "modded into" that range
if isnum is non-NULL, assigns whether stack[idx] was convertible
* luaL_optunsigned(L, idx, lua_Unsigned default)
if stack[idx] isnum, converts to lua_Unsigned
elseif nil returns default, else raises error
* luaL_checkunsigned(L, idx)
if stack[idx] isnum, converts to lua_Unsigned, else raises error
* lua_arith
* lua_compare
replacement for lua_equal and lua_lessthan; all three honor metamethods
* lua_rawlen
replacement for lua_objlen, though doesn't return strlen of a number
* void lua_len(L, idx)
implements # operator, honors __len, pushes any result to stack
* int luaL_len(L, idx)
lua_len --> luaL_checkint on result (converting/returning int)
leaves nothing on stack
* const char *luaL_tolstring(L, idx, size_t *len)
implements native tostring(), result is both returned and pushed,
honors __tostring
* luaL_traceback
* luaL_pushresultsize
* luaL_testudata
* luaL_setmetatable
* lua_rawgetp
* lua_rawsetp
* lua_getuservalue
* lua_setuservalue
the 5.2 version can assign tables or nils, this version only tables
* LUA_RIDX_MAINTHREAD and LUA_RIDX_GLOBALS
but see accompanying LIMITATIONS file
* bool luaL_getsubtable(L, idx, "field")
shallowly ensures stack[idx]["field"] is a table and pushes to stack
returns true if already existed, or false if newly allocated
see also luaQ_getdeeptable, below
* luaL_requiref
calls luaopen_foo and saves result in _G or optionally on stack; see below
* luaL_newlibtable
* luaL_setfuncs -- part of luaL_openlib
* luaL_newlib -- calls luaL_newlibtable then luaL_setfuncs
* luaL_pushmodule -- part of `module` and luaL_openlib/register; see below
* luaL_openlib -- generalizes luaL_register; already exposed if Lua was
compiled with LUA_COMPAT_OPENLIB
Here is the complete list of interfaces that are provided to Lua 5.2:
* lua_equal -- already exposed if Lua was compiled with LUA_COMPAT_ALL
* lua_lessthan -- already exposed if Lua was compiled with LUA_COMPAT_ALL
* lua_objlen -- already exposed if Lua was compiled with LUA_COMPAT_ALL
* lua_strlen -- already exposed if Lua was compiled with LUA_COMPAT_ALL
* lua_cpcall -- already exposed if Lua was compiled with LUA_COMPAT_ALL
* luaL_typerror
* luaL_pushmodule -- already exposed if Lua was compiled with
LUA_COMPAT_MODULE (or LUA_COMPAT_ALL, which implies it)
* luaL_openlib -- already exposed if Lua was compiled with LUA_COMPAT_MODULE
* luaL_register -- already exposed if Lua was compiled with LUA_COMPAT_MODULE
as well as these dinosaurs (there's still some old code around, even on
www.keplerproject.org, and sometimes only the trivial compatibility #defines
from Lua 5.1 are needed to keep it working):
* luaL_getn -- just aliases lua_rawlen
* luaL_setn -- noop
* lua_getregistry
* lua_getgccount
* lua_Chunkreader
* lua_Chunkwriter
* lua_open
* luaL_reg
* luaL_putchar
* lua_ref
* lua_unref
* lua_getref
What do I get when I instead link againt fiveqplus.a?
-----------------------------------------------------
Note that if you're going to link against fiveqplus.a, you need to make sure
LUA_FIVEQ_PLUS is #defined before you #include "fiveq.h".
* void luaL_requiref(L, libname, lua_CFunction luaopen_libname, int gidx)
Runs luaopen_libname (with libname as stack argument) and saves the
return value to package.loaded[libname] and optionally also to
_G[libname].
Lua 5.2's native version uses gidx just as a boolean.
In the version provided to Lua 5.1, and to Lua 5.2 if LUA_FIVEQ_PLUS,
gidx is treated as in Lua 5.2 if it's 0 or 1; but if it has another
value, that is used as an index into the stack. That is, the value
returned from calling luaopen_libname is stored at key libname
in the table at index gidx in the stack, rather than in _G.
As with the native version, a copy of that value is also left on the
stack, and saved in package.loaded[libname].
To use the current environment instead of _G, use:
{ luaQ_getfenv(L, 1, NULL); luaL_requiref(L, "foo", luaopen_foo, -1); }
* void luaQ_checklib(L, "libname")
Unlike luaL_requiref, which runs luaopen_libname, this function
asserts that libname has already been loaded, and pushes
package.loaded[libname] to the stack. If the assertion fails, raises an
error.
* void luaQ_pushmodule(L, "libname", int szhint, int level, "caller")
An optional addition to the Lua 5.2 API is:
void luaL_pushmodule (L, "libname", int szhint);
This is only built if Lua 5.2 is compiled with LUA_COMPAT_MODULE. There
is no difference in the functionality of this bit of code between
Lua 5.1 and Lua 5.2 (when it's built).
fiveq exposes that function for all Lua versions, and fiveqplus
exposes a generalization of it as luaQ_pushmodule.
luaL_pushmodule and luaQ_pushmodule share the following behavior:
They first look for package.loaded[libname] (treating libname as a
single key).
If that fails, and the function is luaL_pushmodule or it's
luaQ_pushmodule with level == 0, they will look "deeply" for a table
named libname in the global environment (here libname is parsed as
possibly consisting of multiple keys separated by "."). When doing so,
they will create any intervening tables as necessary, and will write
the retrieved or new table to package.loaded[libname], as well as
leaving it on the stack.
luaQ_pushmodule can also be called with level > 0. In that case, it
instead looks in the local environment of the function at that call
stack level. (If that function is a CFunction and caller is non-NULL,
it will fail using caller in the error message; if caller is NULL, it
will allow the use of CFunction environments.)
* void luaL_openlib (lua_State *L, const char *libname, const luaL_Reg *A,
int nup)
Combines luaQ_pushmodule and luaL_setfuncs. Like the latter, this
function generalizes luaL_register to allow upvalues. This function
is already exposed in Lua 5.1 if compiled with LUA_COMPAT_OPENLIB, and
in Lua 5.2 if compiled with LUA_COMPAT_MODULE.
When called with libname == NULL, simply calls luaL_setfuncs to
merge the functions in A into the table on top of stack (below
nup upvalues). Afterwards, all upvalues have been popped from stack
but table is left.
If libname != NULL, instead retrieves a new or existing table
from package.loaded[libname] or _G[libname], using luaL_pushmodule.
and registers the functions in A there instead. Afterwards, all
upvalues will have been popped from stack, and the table used will have
been pushed.
In fiveq, this function is always available regardless of how Lua
was compiled. We approximate the behavior of Lua 5.2's version, which
only has these slight differences from Lua 5.1's:
* permits A to be NULL
* checks that enough stack space exists to copy the upvalues
On Lua 5.2, this function (whether provided by fiveq or natively)
starts with a call to luaL_checkversion, which is not available on Lua
5.1.
In fiveqplus, we change this function to look for and register table
libname in the caller's environment, which may differ from _G.
* luaL_register is a shorthand for luaL_openlib with 0 upvalues.
In fiveqplus, it inherits luaL_openlib's "more local" behavior.
* const char *luaQ_getdeeptable(L, idx, "field.field", szhint, &existing)
Based on luaL_findtable from lauxlib.c.
Tries to "deeply" get the table value at stack[idx][fields]: that is,
fields can contain multiple keys separated by "." Contrast
luaL_getsubtable which only searches "shallowly" (always treats its
field argument as a single key).
Creates any intervening tables as necessary (but won't overwrite any
existing non-tables); and if necessary also creates the target table.
If the function succeeds, it returns NULL and the retrieved or new
table will have been pushed onto the stack. If existing is non-NULL,
writes a boolean to it indicating whether the returned table was
pre-existing.
If the function fails (because some existing intervening value isn't a
table), returns a pointer to the problematic parts of fields and an
unaltered stack.
* const char *luaQ_getdeepvalue(L, idx, "field.field")
Like luaQ_getdeepvalue, tries to "deeply" get the value at
stack[idx][fields] (fields can contain multiple keys separated
by "."). However, this function *won't* create any intervening
tables; and doesn't require the target value to be a table.
If successful, returns NULL and the retrieved value (which may
be nil) will have been pushed onto the stack.
If it fails (because some intervening table is missing or isn't
a table), returns a pointer to the problematic parts of fields and
an unaltered stack.
* const char *luaQ_setdeepvalue(L, idx, "field.field")
Tries to "deeply" set stack[idx][fields] to the value at the top
of the stack (fields can contain multiple keys separated by
"."). Creates any intervening tables as necessary (but won't
overwrite any existing non-tables).
If successful, returns NULL and will have popped value from the stack.
If it fails (because some existing intervening value isn't a table),
returns a pointer to the problematic parts of fields and an
unaltered stack.
* void luaQ_getfenv (lua_State *L, int level, const char *caller)
Retrieves the environment table of the function at call stack
level. If caller is NULL, permits the function at that level
to be a C function.
Note that in 5.1 but not 5.2, tail calls increment the "level".
In 5.2, searches locals and upvalues at that stack level for _ENV.
If level == 0, returns the global table instead.
* void luaQ_setfenv (lua_State *L, int level, const char *fname)
Pops table from stack and assigns it as environment of function
at call stack `level`. If caller is NULL, permits the function
at that level to be a C function.
Note that in 5.1 but not 5.2, tail calls increment the "level".
In 5.2, searches locals and upvalues at that stack level for _ENV.
Why are there so many different ways to expose my library functions to Lua?
---------------------------------------------------------------------------
Yes, there *are* a number of functions associated with that task:
* luaL_requiref
* lua_register
* luaL_setfuncs
* luaL_newlib
* luaL_pushmodule
* luaL_openlib
* luaL_register
and fiveqplus adds luaQ_checklib and luaQ_pushmodule. Here are some notes to
sort out the differences. All of these C functions return void.
luaL_requiref(L, "libname", luaopen_libname, gidx):
Runs luaopen_libname and saves the return value to
package.loaded[libname] and optionally also to global or
caller's environment
* "libname" may be NULL, but this has no special effect
* when gidx == 0: only save return value in package.loaded[libname]
* when gidx == 1: also save the return value to key "libname" in
the global environment
* when fiveqplus and gidx is neither 0 nor 1: use the table at
stack[gidx] instead of _G
* in all cases, the return value from luaopen_libname is also left
on the stack
luaQ_checklib(L, "libname")
Asserts that Lua has already loaded library libname, and
pushes it to the stack. If the assertion fails, raises an error.
lua_register(L, "funcname", f):
assigns the lua_CFunction f (with no upvalues) to the key
"funcname" in the global environment.
luaL_setfuncs is a generalization that works with an array of
functions, permits giving them shared upvalues, and uses
a table on the stack instead of the global environment.
luaL_setfuncs(L, luaL_Reg *A, int nup);
part of the implementation of luaL_openlib;
merges functions from A, with nup shared upvalues, into the
table immediately below the upvalues on the top of the stack.
pops upvalues but leaves table on stack
luaL_newlib(L, luaL_Reg *A);
allocate a new table and call luaL_setfuncs with nup = 0
luaQ_pushmodule(L, "libname", szhint, int level, "caller");
looks shallowly for "libname" in package.loaded, then
"deeply" for it in the global environment (or in the environment
at call stack level if that's > 0; if "caller" is non-NULL,
that caller must be a Lua function).
Creates intervening tables as necessary, saves the table
in package.loaded, and leaves it on stack.
luaL_pushmodule(L, "libname", szhint);
part of the implementation of `module` and luaL_openlib/register.
specializes luaQ_pushmodule to case where level == 0.
luaL_openlib(L, "libname", luaL_Reg *A, int nup);
* libname == NULL: simply calls luaL_setfuncs(L, A, nup);
* libname != NULL: instead of table already on the stack,
uses a new or existing table from package.loaded[libname] or
_G[libname]. This is retrieved using luaL_pushmodule.
* when fiveqplus and libname != NULL: uses caller's environment
_ENV in place of _G.
* in all cases, table that A has been merged into is left on stack
luaL_register(L, "libname", luaL_Reg *A);
specializes luaL_openlib to case where there are no upvalues
Three typical patterns for a luaopen_foo function are:
static const luaL_Reg foolib[] = {
{"func1name", func1},
{"func2name", func2},
{NULL, NULL}
};
extern int luaopen_foo(lua_State *L) {
luaL_newlib(L, foolib);
/* same as: lua_newtable(L); luaL_setfuncs(L, foolib, 0); */
/* same as: lua_newtable(L); luaL_openlib(L, NULL, foolib, 0); */
return 1;
}
then when this library is loaded by calling `require "foo"` from Lua, or
luaL_requiref(L, "foo", luaopen_foo, 0)
from C, the table containing func1 and func2 will be saved in
package.loaded["foo"].
Another pattern writes the functions to an existing table:
static const luaL_Reg foolib[] = ...
extern int luaopen_foo(lua_State *L) {
luaQ_checklib(L, LUA_STRLIBNAME); luaL_setfuncs(L, foolib, 0);
/* similar: luaL_openlib(L, LUA_STRLIBNAME, foolib, 0); */
return 0;
}
A third pattern writes the functions directly to the global table (or in
fiveglueplus, to the caller's environment table):
static const luaL_Reg foolib[] = ...
extern int luaopen_foo(lua_State *L) {
/* write a single function to _G */
lua_register(L, "func0name", func0):
/* write array foolib of functions to _G or to caller's _ENV */
luaL_openlib(L, "foo", foolib, 0);
/* same as: luaL_register(L, "foo", foolib); */
/* foo library is still on stack; may or may not want to return it */
return 0;
}