2016-02-11 16:57:57 +00:00
|
|
|
/*
|
|
|
|
* Lua safe functions
|
|
|
|
*
|
|
|
|
* Copyright 2015-2016 Thierry Fournier <tfournier@arpalert.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* All the functions in this file runs with a Lua stack, and can
|
2016-01-21 08:28:58 +00:00
|
|
|
* return with a longjmp. All of these function must be launched
|
|
|
|
* in an environment able to catch a longjmp, otherwise a
|
|
|
|
* critical error can be raised.
|
|
|
|
*/
|
|
|
|
#include <lauxlib.h>
|
|
|
|
#include <lua.h>
|
|
|
|
#include <lualib.h>
|
|
|
|
|
2016-01-21 08:46:15 +00:00
|
|
|
#include <common/time.h>
|
|
|
|
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
#include <types/hlua.h>
|
|
|
|
|
2016-01-27 08:49:07 +00:00
|
|
|
/* Contains the class reference of the concat object. */
|
|
|
|
static int class_concat_ref;
|
|
|
|
|
2016-01-27 08:55:30 +00:00
|
|
|
/* Return an object of the expected type, or throws an error. */
|
|
|
|
void *hlua_checkudata(lua_State *L, int ud, int class_ref)
|
|
|
|
{
|
|
|
|
void *p;
|
2016-01-27 09:34:09 +00:00
|
|
|
int ret;
|
2016-01-27 08:55:30 +00:00
|
|
|
|
|
|
|
/* Check if the stack entry is an array. */
|
|
|
|
if (!lua_istable(L, ud))
|
2016-01-27 09:34:09 +00:00
|
|
|
luaL_argerror(L, ud, NULL);
|
|
|
|
|
|
|
|
/* pop the metatable of the referencecd object. */
|
|
|
|
if (!lua_getmetatable(L, ud))
|
|
|
|
luaL_argerror(L, ud, NULL);
|
|
|
|
|
|
|
|
/* pop the expected metatable. */
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, class_ref);
|
|
|
|
|
2016-01-27 08:55:30 +00:00
|
|
|
/* Check if the metadata have the expected type. */
|
2016-01-27 09:34:09 +00:00
|
|
|
ret = lua_rawequal(L, -1, -2);
|
|
|
|
lua_pop(L, 2);
|
|
|
|
if (!ret)
|
|
|
|
luaL_argerror(L, ud, NULL);
|
|
|
|
|
2016-01-27 08:55:30 +00:00
|
|
|
/* Push on the stack at the entry [0] of the table. */
|
|
|
|
lua_rawgeti(L, ud, 0);
|
2016-01-27 09:34:09 +00:00
|
|
|
|
2016-01-27 08:55:30 +00:00
|
|
|
/* Check if this entry is userdata. */
|
|
|
|
p = lua_touserdata(L, -1);
|
|
|
|
if (!p)
|
2016-01-27 09:34:09 +00:00
|
|
|
luaL_argerror(L, ud, NULL);
|
|
|
|
|
2016-01-27 08:55:30 +00:00
|
|
|
/* Remove the entry returned by lua_rawgeti(). */
|
|
|
|
lua_pop(L, 1);
|
2016-01-27 09:34:09 +00:00
|
|
|
|
2016-01-27 08:55:30 +00:00
|
|
|
/* Return the associated struct. */
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2016-01-21 08:46:15 +00:00
|
|
|
/* This function return the current date at epoch format in milliseconds. */
|
|
|
|
int hlua_now(lua_State *L)
|
|
|
|
{
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, "sec");
|
|
|
|
lua_pushinteger(L, now.tv_sec);
|
|
|
|
lua_rawset(L, -3);
|
|
|
|
lua_pushstring(L, "usec");
|
|
|
|
lua_pushinteger(L, now.tv_usec);
|
|
|
|
lua_rawset(L, -3);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-01-21 08:35:41 +00:00
|
|
|
/* This functions expects a Lua string as HTTP date, parse it and
|
|
|
|
* returns an integer containing the epoch format of the date, or
|
|
|
|
* nil if the parsing fails.
|
|
|
|
*/
|
|
|
|
static int hlua_parse_date(lua_State *L, int (*fcn)(const char *, int, struct tm*))
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
size_t len;
|
|
|
|
struct tm tm;
|
|
|
|
time_t time;
|
|
|
|
|
|
|
|
str = luaL_checklstring(L, 1, &len);
|
|
|
|
|
|
|
|
if (!fcn(str, len, &tm)) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function considers the content of the broken-down time
|
|
|
|
* is exprimed in the UTC timezone. timegm don't care about
|
|
|
|
* the gnu variable tm_gmtoff. If gmtoff is set, or if you know
|
|
|
|
* the timezone from the broken-down time, it must be fixed
|
|
|
|
* after the conversion.
|
|
|
|
*/
|
|
|
|
time = timegm(&tm);
|
|
|
|
if (time == -1) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_pushinteger(L, (int)time);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static int hlua_http_date(lua_State *L)
|
|
|
|
{
|
|
|
|
return hlua_parse_date(L, parse_http_date);
|
|
|
|
}
|
|
|
|
static int hlua_imf_date(lua_State *L)
|
|
|
|
{
|
|
|
|
return hlua_parse_date(L, parse_imf_date);
|
|
|
|
}
|
|
|
|
static int hlua_rfc850_date(lua_State *L)
|
|
|
|
{
|
|
|
|
return hlua_parse_date(L, parse_rfc850_date);
|
|
|
|
}
|
|
|
|
static int hlua_asctime_date(lua_State *L)
|
|
|
|
{
|
|
|
|
return hlua_parse_date(L, parse_asctime_date);
|
|
|
|
}
|
|
|
|
|
2016-01-21 08:28:58 +00:00
|
|
|
static void hlua_array_add_fcn(lua_State *L, const char *name,
|
|
|
|
int (*function)(lua_State *L))
|
|
|
|
{
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
lua_pushcclosure(L, function, 0);
|
|
|
|
lua_rawset(L, -3);
|
|
|
|
}
|
|
|
|
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
static struct hlua_concat *hlua_check_concat(lua_State *L, int ud)
|
2016-01-27 08:49:07 +00:00
|
|
|
{
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
return (struct hlua_concat *)(hlua_checkudata(L, ud, class_concat_ref));
|
2016-01-27 08:49:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int hlua_concat_add(lua_State *L)
|
|
|
|
{
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
struct hlua_concat *b;
|
|
|
|
char *buffer;
|
|
|
|
char *new;
|
2016-01-27 08:49:07 +00:00
|
|
|
const char *str;
|
|
|
|
size_t l;
|
|
|
|
|
|
|
|
/* First arg must be a concat object. */
|
|
|
|
b = hlua_check_concat(L, 1);
|
|
|
|
|
|
|
|
/* Second arg must be a string. */
|
|
|
|
str = luaL_checklstring(L, 2, &l);
|
|
|
|
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
/* Get the buffer. */
|
|
|
|
lua_rawgeti(L, 1, 1);
|
|
|
|
buffer = lua_touserdata(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
/* Update the buffer size if it s required. The old buffer
|
|
|
|
* is crushed by the new in the object array, so it will
|
|
|
|
* be deleted by the GC.
|
|
|
|
* Note that in the first loop, the "new" variable is only
|
|
|
|
* used as a flag.
|
|
|
|
*/
|
|
|
|
new = NULL;
|
|
|
|
while (b->size - b->len < l) {
|
|
|
|
b->size += HLUA_CONCAT_BLOCSZ;
|
|
|
|
new = buffer;
|
|
|
|
}
|
|
|
|
if (new) {
|
|
|
|
new = lua_newuserdata(L, b->size);
|
|
|
|
memcpy(new, buffer, b->len);
|
|
|
|
lua_rawseti(L, 1, 1);
|
|
|
|
buffer = new;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy string, and update metadata. */
|
|
|
|
memcpy(buffer + b->len, str, l);
|
|
|
|
b->len += l;
|
2016-01-27 08:49:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hlua_concat_dump(lua_State *L)
|
|
|
|
{
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
struct hlua_concat *b;
|
|
|
|
char *buffer;
|
2016-01-27 08:49:07 +00:00
|
|
|
|
|
|
|
/* First arg must be a concat object. */
|
|
|
|
b = hlua_check_concat(L, 1);
|
|
|
|
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
/* Get the buffer. */
|
|
|
|
lua_rawgeti(L, 1, 1);
|
|
|
|
buffer = lua_touserdata(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2016-01-27 08:49:07 +00:00
|
|
|
/* Push the soncatenated strng in the stack. */
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
lua_pushlstring(L, buffer, b->len);
|
2016-01-27 08:49:07 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hlua_concat_new(lua_State *L)
|
|
|
|
{
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
struct hlua_concat *b;
|
2016-01-27 08:49:07 +00:00
|
|
|
|
|
|
|
lua_newtable(L);
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
b = (struct hlua_concat *)lua_newuserdata(L, sizeof(*b));
|
|
|
|
b->size = HLUA_CONCAT_BLOCSZ;
|
|
|
|
b->len = 0;
|
2016-01-27 08:49:07 +00:00
|
|
|
lua_rawseti(L, -2, 0);
|
BUG/MAJOR: lua: segfault using Concat object
Concat object is based on "luaL_Buffer". The luaL_Buffer documentation says:
During its normal operation, a string buffer uses a variable number of stack
slots. So, while using a buffer, you cannot assume that you know where the
top of the stack is. You can use the stack between successive calls to buffer
operations as long as that use is balanced; that is, when you call a buffer
operation, the stack is at the same level it was immediately after the
previous buffer operation. (The only exception to this rule is
luaL_addvalue.) After calling luaL_pushresult the stack is back to its level
when the buffer was initialized, plus the final string on its top.
So, the stack cannot be manipulated between the first call at the function
"luaL_buffinit()" and the last call to the function "luaL_pushresult()" because
we cannot known the stack status.
In other way, the memory used by these functions seems to be collected by GC, so
if the GC is triggered during the usage of the Concat object, it can be used
some released memory.
This patch rewrite the Concat class without the "luaL_Buffer" system. It uses
"userdata()" forr the memory allocation of the buffer strings.
2016-02-19 11:09:29 +00:00
|
|
|
lua_newuserdata(L, HLUA_CONCAT_BLOCSZ);
|
|
|
|
lua_rawseti(L, -2, 1);
|
2016-01-27 08:49:07 +00:00
|
|
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, class_concat_ref);
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int concat_tostring(lua_State *L)
|
|
|
|
{
|
|
|
|
const void *ptr = lua_topointer(L, 1);
|
|
|
|
lua_pushfstring(L, "Concat object: %p", ptr);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hlua_concat_init(lua_State *L)
|
|
|
|
{
|
|
|
|
/* Creates the buffered concat object. */
|
|
|
|
lua_newtable(L);
|
|
|
|
|
|
|
|
lua_pushstring(L, "__tostring");
|
|
|
|
lua_pushcclosure(L, concat_tostring, 0);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "__index"); /* Creates the index entry. */
|
|
|
|
lua_newtable(L); /* The "__index" content. */
|
|
|
|
|
|
|
|
lua_pushstring(L, "add");
|
|
|
|
lua_pushcclosure(L, hlua_concat_add, 0);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "dump");
|
|
|
|
lua_pushcclosure(L, hlua_concat_dump, 0);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_settable(L, -3); /* Sets the __index entry. */
|
|
|
|
class_concat_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-01-21 08:28:58 +00:00
|
|
|
int hlua_fcn_reg_core_fcn(lua_State *L)
|
|
|
|
{
|
2016-01-27 08:49:07 +00:00
|
|
|
if (!hlua_concat_init(L))
|
|
|
|
return 0;
|
|
|
|
|
2016-01-21 08:46:15 +00:00
|
|
|
hlua_array_add_fcn(L, "now", hlua_now);
|
2016-01-21 08:35:41 +00:00
|
|
|
hlua_array_add_fcn(L, "http_date", hlua_http_date);
|
|
|
|
hlua_array_add_fcn(L, "imf_date", hlua_imf_date);
|
|
|
|
hlua_array_add_fcn(L, "rfc850_date", hlua_rfc850_date);
|
|
|
|
hlua_array_add_fcn(L, "asctime_date", hlua_asctime_date);
|
2016-01-27 08:49:07 +00:00
|
|
|
hlua_array_add_fcn(L, "concat", hlua_concat_new);
|
2016-01-21 08:35:41 +00:00
|
|
|
return 5;
|
2016-01-21 08:28:58 +00:00
|
|
|
}
|