首页 > 代码库 > 改写 alien core使其可以适配lua5.3

改写 alien core使其可以适配lua5.3

/* Lua FFI using libffi */
/* Author: Fabio Mascarenhas */
/* License: MIT/X11 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "ffi.h"


#ifdef WINDOWS
#include <windows.h>
#define ALLOCA _alloca
#else
#include <sys/mman.h>
#include <unistd.h>
# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#  define MAP_ANONYMOUS MAP_ANON
# endif
#define ALLOCA alloca
#endif


#define BLOCKSIZE _pagesize


#define ALIEN_LIBRARY_META "alien_library"
#define ALIEN_FUNCTION_META "alien_function"
#define ALIEN_BUFFER_META "alien_buffer"
#define ALIEN_CALLBACK_META "alien_callback"


#ifndef uchar
#define uchar unsigned char
#endif


typedef enum {
  AT_SHORT,
  AT_INT,
  AT_LONG,
  AT_VOID,
  AT_FLOAT,
  AT_DOUBLE,
  AT_CHAR,
  AT_BYTE,
  AT_STRING,
  AT_PTR,
  AT_REFINT,
  AT_REFCHAR,
  AT_REFDOUBLE,
  AT_CALLBACK
} alien_Type;


typedef struct _alien_Library {
  void *lib;
  char *name;
} alien_Library;


typedef struct _alien_Function {
  alien_Library *lib;
  void *fn;
  char *name;
  alien_Type ret_type;
  ffi_cif cif;
  ffi_type *ffi_ret_type;
  int nparams;
  alien_Type *params;
  ffi_type **ffi_params;
} alien_Function;


typedef struct _alien_Callback {
  /* alien_Function part! */
  alien_Library *lib;
  void *fn;
  char *name;
  alien_Type ret_type;
  ffi_cif cif;
  ffi_type *ffi_ret_type;
  int nparams;
  alien_Type *params;
  ffi_type **ffi_params;
  /* callback part */
  lua_State *L;
  int fn_ref;
} alien_Callback;


typedef struct _alien_Wrap {
  alien_Type tag;
  union {
    void *p;
    int i;
  } val;
} alien_Wrap;


typedef union _tagITEM {
ffi_closure closure;
union _tagITEM *next;
} ITEM;


static ITEM *free_list;
int _pagesize;


/* Information to compute strucuture access */


typedef struct { char c; char x; } s_char;
typedef struct { char c; short x; } s_short;
typedef struct { char c; int x; } s_int;
typedef struct { char c; long x; } s_long;
typedef struct { char c; float x; } s_float;
typedef struct { char c; double x; } s_double;
typedef struct { char c; char *x; } s_char_p;
typedef struct { char c; void *x; } s_void_p;


#define AT_CHAR_ALIGN (sizeof(s_char) - sizeof(char))
#define AT_SHORT_ALIGN (sizeof(s_short) - sizeof(short))
#define AT_INT_ALIGN (sizeof(s_int) - sizeof(int))
#define AT_LONG_ALIGN (sizeof(s_long) - sizeof(long))
#define AT_FLOAT_ALIGN (sizeof(s_float) - sizeof(float))
#define AT_DOUBLE_ALIGN (sizeof(s_double) - sizeof(double))
#define AT_CHAR_P_ALIGN (sizeof(s_char_p) - sizeof(char*))
#define AT_VOID_P_ALIGN (sizeof(s_void_p) - sizeof(void*))


static void more_core(void)
{
ITEM *item;
int count, i;


/* determine the pagesize */
#ifdef WINDOWS
if (!_pagesize) {
SYSTEM_INFO systeminfo;
GetSystemInfo(&systeminfo);
_pagesize = systeminfo.dwPageSize;
}
#else
if (!_pagesize) {
_pagesize = getpagesize();
}
#endif


/* calculate the number of nodes to allocate */
count = BLOCKSIZE / sizeof(ITEM);


/* allocate a memory block */
#ifdef WINDOWS
item = (ITEM *)VirtualAlloc(NULL,
      count * sizeof(ITEM),
      MEM_COMMIT,
      PAGE_EXECUTE_READWRITE);
if (item == NULL)
return;
#else
item = (ITEM *)mmap(NULL,
   count * sizeof(ITEM),
   PROT_READ | PROT_WRITE | PROT_EXEC,
   MAP_PRIVATE | MAP_ANONYMOUS,
   -1,
   0);
if (item == (void *)MAP_FAILED)
return;
#endif


/* put them into the free list */
for (i = 0; i < count; ++i) {
item->next = free_list;
free_list = item;
++item;
}
}


/******************************************************************/


/* put the item back into the free list */
void free_closure(void *p)
{
ITEM *item = (ITEM *)p;
item->next = free_list;
free_list = item;
}


/* return one item from the free list, allocating more if needed */
void *malloc_closure(void)
{
ITEM *item;
if (!free_list)
more_core();
if (!free_list)
return NULL;
item = free_list;
free_list = item->next;
return item;
}


#if defined(LINUX)
#define PLATFORM "linux"
#define USE_DLOPEN
#elif defined(BSD)
#define PLATFORM "bsd"
#define USE_DLOPEN
#elif defined(DARWIN)
#define PLATFORM "darwin"
#define USE_DLOPEN
#endif


#if defined(USE_DLOPEN)


#ifndef RTLD_DEFAULT
#define RTLD_DEFAULT 0
#endif


#include <dlfcn.h>


static void alien_unload (void *lib) {
  if(lib && (lib != RTLD_DEFAULT))
    dlclose(lib);
}


static void *alien_load (lua_State *L, const char *libname) {
  void *lib;
  lib = dlopen(libname, RTLD_NOW);
  if(lib == NULL) lua_pushstring(L, dlerror());
  return lib;
}


static void *alien_loadfunc (lua_State *L, void *lib, const char *sym) {
  if(!lib) lib = RTLD_DEFAULT;
  void *f = dlsym(lib, sym);
  if (f == NULL) lua_pushstring(L, dlerror());
  return f;
}


#elif defined(WINDOWS)


#define PLATFORM "windows"


static void pusherror (lua_State *L) {
  int error = GetLastError();
  char buffer[128];
  if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
      NULL, error, 0, buffer, sizeof(buffer), NULL))
    lua_pushstring(L, buffer);
  else
    lua_pushfstring(L, "system error %d\n", error);
}


static void alien_unload (void *lib) {
  if(lib)
    FreeLibrary((HINSTANCE)lib);
}


static void *alien_load (lua_State *L, const char *libname) {
  HINSTANCE lib = LoadLibrary(libname);
  if (lib == NULL) pusherror(L);
  return lib;
}


static void *alien_loadfunc (lua_State *L, void *lib, const char *sym) {
  HINSTANCE module;
  void *f;
  module = (HINSTANCE)lib;
  if(!module) module = GetModuleHandle(NULL);
  f = (lua_CFunction)GetProcAddress(module, sym);
  if (f == NULL) pusherror(L);
  return f;
}


#else


#define DLMSG   "dynamic libraries not enabled; check your Lua installation"


#define PLATFORM "unknown"


static void alien_unload (void *lib) {
  (void)lib;  /* to avoid warnings */
}


static void *alien_load (lua_State *L, const char *path) {
  (void)path;  /* to avoid warnings */
  lua_pushliteral(L, DLMSG);
  return NULL;
}


static void *alien_loadfunc (lua_State *L, void *lib, const char *sym) {
  (void)lib; (void)sym;  /* to avoid warnings */
  lua_pushliteral(L, DLMSG);
  return NULL;
}


#endif


#ifndef WINDOWS
#define FFI_STDCALL FFI_DEFAULT_ABI
#endif


#ifdef DARWIN
#define FFI_SYSV FFI_DEFAULT_ABI
#endif


static const ffi_abi ffi_abis[] = { FFI_DEFAULT_ABI, FFI_SYSV, FFI_STDCALL };
static const char *const ffi_abi_names[] = { "default", "cdecl", "stdcall", NULL };


static alien_Library *alien_checklibrary(lua_State *L, int index) {
  void *ud = luaL_checkudata(L, index, ALIEN_LIBRARY_META);
  luaL_argcheck(L, ud != NULL, index, "alien library expected");
  return (alien_Library *)ud;
}


static alien_Function *alien_checkfunction(lua_State *L, int index) {
  luaL_getmetatable(L, ALIEN_FUNCTION_META);
  lua_getmetatable(L, index);
  if(lua_rawequal(L, -1, -2)) {
    lua_pop(L, 2);
    return (alien_Function *)lua_touserdata(L, index);
  }
  lua_pop(L, 2);
  luaL_getmetatable(L, ALIEN_CALLBACK_META);
  lua_getmetatable(L, index);
  if(lua_rawequal(L, -1, -2)) {
    ffi_closure *ud = *((ffi_closure**)lua_touserdata(L, index));
    lua_pop(L, 2);
    return (alien_Function *)ud->user_data;
  }
  lua_pop(L, 2);
  luaL_argcheck(L, 0, index, "alien function expected");
  return NULL;
}


static ffi_closure *alien_checkcallback(lua_State *L, int index) {
  void *ud = luaL_checkudata(L, index, ALIEN_CALLBACK_META);
  luaL_argcheck(L, ud != NULL, index, "alien callback expected");
  return *((ffi_closure **)ud);
}


static char *alien_checkbuffer(lua_State *L, int index) {
  void *ud = luaL_checkudata(L, index, ALIEN_BUFFER_META);
  luaL_argcheck(L, ud != NULL, index, "alien buffer expected");
  return (char *)ud;
}


static int alien_get(lua_State *L) {
  char *name;
  const char *libname;
  size_t len;
  libname = luaL_checklstring(L, lua_gettop(L), &len);
  name = (char*)malloc(sizeof(char) * (len + 1));
  if(name) {
    void *lib;
    alien_Library *al;
    strcpy(name, libname);
    al = (alien_Library *)lua_newuserdata(L, sizeof(alien_Library));
    if(!al) luaL_error(L, "out of memory!");
    lib = alien_load(L, libname);
    if(lib) {
      luaL_getmetatable(L, ALIEN_LIBRARY_META);
      lua_setmetatable(L, -2);
      al->lib = lib;
      al->name = name;
      return 1;
    } else {
      lua_error(L);
    }
  } else {
    luaL_error(L, "out of memory!");
  }
  return 0;
}


static int alien_makefunction(lua_State *L, void *lib, void *fn, char *name) {
  alien_Function *af;
  af = (alien_Function *)lua_newuserdata(L, sizeof(alien_Function));
  if(af) {
    luaL_getmetatable(L, ALIEN_FUNCTION_META);
    lua_setmetatable(L, -2);
    af->fn = fn;
    af->name = name;
    af->lib = lib;
    af->nparams = 0;
    af->ret_type = AT_VOID;
    af->params = NULL;
  } else luaL_error(L, "out of memory!");
  return 1;
}


static int alien_library_get(lua_State *L) {
  const char *funcname;
  char *name;
  size_t len;
  funcname = luaL_checklstring(L, 2, &len);
  lua_getfield(L, lua_upvalueindex(1), funcname);
  if(!lua_isnil(L, -1)) return 1;
  name = (char*)malloc(sizeof(char) * (len + 1));
  if(name) {
    alien_Library *al;
    void *fn;
    strcpy(name, funcname);
    al = alien_checklibrary(L, 1);
    fn = alien_loadfunc(L, al->lib, funcname);
    if(fn) {
      alien_makefunction(L, al, fn, name);
      lua_pushvalue(L, -1);
      lua_setfield(L, lua_upvalueindex(1), funcname);
      return 1;
    } else {
      free(name);
      lua_error(L);
    }
  } else {
    luaL_error(L, "out of memory!");
  }
  return 0;
}


static int alien_function_new(lua_State *L) {
  void *fn;
  if(lua_isuserdata(L, 1)) {
    void *fn = lua_touserdata(L, 1);
    return alien_makefunction(L, NULL, fn, NULL);
  } else luaL_error(L, "alien: not an userdata");
  return 0;
}


static int alien_library_tostring(lua_State *L) {
  alien_Library *al;
  al = alien_checklibrary(L, 1);
  lua_pushfstring(L, "alien library %s", (al->name ? al->name : "default"));
  return 1;
}


static void alien_callback_call(ffi_cif *cif, void *resp, void **args, void *data) {
  alien_Callback *ac;
  int nparams, i;
  void *ptr;
  ac = (alien_Callback *)data;
  lua_rawgeti(ac->L, LUA_REGISTRYINDEX, ac->fn_ref);
  //lua_getref(ac->L, ac->fn_ref);
  nparams = ac->nparams;
  for(i = 0; i < nparams; i++) {
    switch(ac->params[i]) {
    case AT_BYTE: lua_pushnumber(ac->L, (signed char)*((int*)args[i])); break;
    case AT_CHAR: lua_pushnumber(ac->L, (uchar)*((int*)args[i])); break;
    case AT_SHORT: lua_pushnumber(ac->L, (short)*((int*)args[i])); break;
    case AT_LONG: 
      lua_pushnumber(ac->L, (long)*((long*)args[i])); break;
    case AT_INT: lua_pushnumber(ac->L, *((int*)args[i])); break;
    case AT_FLOAT: lua_pushnumber(ac->L, (float)*((float*)args[i])); break;
    case AT_DOUBLE: lua_pushnumber(ac->L, *((double*)args[i])); break;
    case AT_STRING: lua_pushstring(ac->L, *((char**)args[i])); break;
    case AT_REFINT: 
      lua_pushnumber(ac->L, **((int**)args[i])); break;
    case AT_REFCHAR:
      lua_pushnumber(ac->L, **((uchar**)args[i])); break;
    case AT_REFDOUBLE: 
      lua_pushnumber(ac->L, **((double**)args[i])); break;
    case AT_PTR:
      ptr = *((void**)args[i]);
      ptr ? lua_pushlightuserdata(ac->L, ptr) : lua_pushnil(ac->L);
      break;
    default: luaL_error(ac->L, "alien: unknown parameter type in callback");
    }
  }
  lua_call(ac->L, nparams, 1);
  switch(ac->ret_type) {
  case AT_VOID: break;
  case AT_SHORT: *((int*)resp) = (short)lua_tointeger(ac->L, -1); break;
  case AT_LONG: 
    *((long*)resp) = (long)lua_tointeger(ac->L, -1); break;
  case AT_INT: *((int*)resp) = (int)lua_tointeger(ac->L, -1); break;
  case AT_CHAR: *((int*)resp) = (uchar)lua_tointeger(ac->L, -1); break;
  case AT_BYTE: *((int*)resp) = (signed char)lua_tointeger(ac->L, -1); break;
  case AT_FLOAT: *((float*)resp) = (float)lua_tonumber(ac->L, -1); break;
  case AT_DOUBLE: *((double*)resp) = (double)lua_tonumber(ac->L, -1); break;
  case AT_STRING:
    if(lua_isuserdata(ac->L, -1))
      *((char**)resp) = lua_touserdata(ac->L, -1);
    else
      *((const char**)resp) = lua_tostring(ac->L, -1); 
    break;
  case AT_PTR:
    if(lua_isstring(ac->L, -1))
      *((void**)resp) = (void*)lua_tostring(ac->L, -1);
    else
      *((void**)resp) = lua_touserdata(ac->L, -1);
    break;
  default: luaL_error(ac->L, "alien: unknown return type in callback");
  }
}


static int alien_callback_new(lua_State *L) {
  int fn_ref;
  alien_Callback *ac;
  alien_Type at;
  ffi_closure **ud;
  int i, nparams;
  ffi_status status;
  ffi_abi abi;
  static ffi_type *const ffitypes[] = {&ffi_type_void, &ffi_type_sint, &ffi_type_double, 
&ffi_type_uchar, &ffi_type_pointer, &ffi_type_pointer,
&ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer,
&ffi_type_pointer, &ffi_type_sshort, &ffi_type_schar,
#ifndef WINDOWS
&ffi_type_slong, 
#else
&ffi_type_sint,
#endif
&ffi_type_float};
  static int const types[] = {AT_VOID, AT_INT, AT_DOUBLE, AT_CHAR, AT_STRING, AT_PTR, AT_REFINT, 
     AT_REFDOUBLE, AT_REFCHAR, AT_CALLBACK, AT_SHORT, AT_BYTE, AT_LONG,
     AT_FLOAT};
  static const char *const typenames[] = 
    {"void", "int", "double", "char", "string", "pointer",
     "ref int", "ref double", "ref char", "callback", 
     "short", "byte", "long", "float", NULL};
  luaL_checktype(L, 1, LUA_TFUNCTION);
  if(lua_istable(L, 2)) {
    //nparams = lua_objlen(L, 2);
 nparams = lua_rawlen(L, 2);
  } else {
    nparams = lua_gettop(L) - 2;
  }
  ac = (alien_Callback *)malloc(sizeof(alien_Callback));
  ud = (ffi_closure **)lua_newuserdata(L, sizeof(ffi_closure**));
  if(ac != NULL && ud != NULL) {
    int j;
    *ud = malloc_closure();
    if(*ud == NULL) { free(ac); luaL_error(L, "alien: cannot allocate callback"); }
    ac->L = L;
    if(lua_istable(L, 2)) {
      lua_getfield(L, 2, "ret");
      ac->ret_type = types[luaL_checkoption(L, -1, "int", typenames)];
      ac->ffi_ret_type = ffitypes[luaL_checkoption(L, -1, "int", typenames)];
      lua_getfield(L, 2, "abi");
      abi = ffi_abis[luaL_checkoption(L, -1, "default", ffi_abi_names)];
      lua_pop(L, 2);
    } else {
      ac->ret_type = types[luaL_checkoption(L, 2, "int", typenames)];
      ac->ffi_ret_type = ffitypes[luaL_checkoption(L, 2, "int", typenames)];
      abi = FFI_DEFAULT_ABI;
    }
    ac->nparams = nparams;
    if(ac->nparams > 0) {
      ac->params = (alien_Type *)malloc(ac->nparams * sizeof(alien_Type));
      if(!ac->params) luaL_error(L, "alien: out of memory");
      ac->ffi_params = (ffi_type **)malloc(ac->nparams * sizeof(ffi_type*));
      if(!ac->ffi_params) luaL_error(L, "alien: out of memory");
    }
    if(lua_istable(L, 2)) {
      for(i = 0, j = 1; i < ac->nparams; i++, j++) {
lua_rawgeti(L, 2, j);
ac->ffi_params[i] = ffitypes[luaL_checkoption(L, -1, "int", typenames)];
ac->params[i] = types[luaL_checkoption(L, -1, "int", typenames)];
lua_pop(L, 1);
      }
    } else {
      for(i = 0, j = 3; i < ac->nparams; i++, j++) {
ac->ffi_params[i] = ffitypes[luaL_checkoption(L, j, "int", typenames)];
ac->params[i] = types[luaL_checkoption(L, j, "int", typenames)];
      }
    }
    lua_pushvalue(L, 1);
    //ac->fn_ref = lua_ref(L, 1);
ac->fn_ref = luaL_ref(L, 1);
    luaL_getmetatable(L, ALIEN_CALLBACK_META);
    lua_setmetatable(L, -2);
    status = ffi_prep_cif(&(ac->cif), abi, ac->nparams,
 ac->ffi_ret_type, ac->ffi_params);
    if(status != FFI_OK) luaL_error(L, "alien: cannot create callback");
    status = ffi_prep_closure(*ud, &(ac->cif), &alien_callback_call, ac);
    ac->fn = *ud;
    ac->lib = NULL;
    ac->name = NULL;
    if(status != FFI_OK) luaL_error(L, "alien: cannot create callback");
    return 1;
  } else {
    if(ac) free(ac);
    luaL_error(L, "alien: cannot allocate callback");
  }
  return 0;
}


static int alien_sizeof(lua_State *L) {
  static const int sizes[] = {sizeof(int), sizeof(double), sizeof(uchar), 
     sizeof(char*), sizeof(void*), sizeof(char),
     sizeof(short), sizeof(long), sizeof(float),
                              sizeof(void*), sizeof(char*), sizeof(int*),
                              sizeof(double*)};
  static const char *const typenames[] = {"int", "double", "char", "string", 
 "pointer", "byte", "short", "long",
 "float", "callback", "ref char",
 "ref int", "ref double", NULL};
  lua_pushnumber(L, sizes[luaL_checkoption(L, 1, "int", typenames)]);
  return 1;
}


static int alien_align(lua_State *L) {
  static const int aligns[] = {AT_INT_ALIGN, AT_DOUBLE_ALIGN, AT_CHAR_ALIGN, 
     AT_CHAR_P_ALIGN, AT_VOID_P_ALIGN, AT_CHAR_ALIGN,
     AT_SHORT_ALIGN, AT_LONG_ALIGN, AT_FLOAT_ALIGN,
     AT_VOID_P_ALIGN, AT_CHAR_P_ALIGN, AT_VOID_P_ALIGN,
      AT_VOID_P_ALIGN};
  static const char *const typenames[] = {"int", "double", "char", "string", 
 "pointer", "byte", "short", "long",
 "float", "callback", "ref char",
 "ref int", "ref double", NULL};
  lua_pushnumber(L, aligns[luaL_checkoption(L, 1, "char", typenames)]);
  return 1;
}


static int alien_function_types(lua_State *L) {
  static ffi_type* ffitypes[] = {&ffi_type_void, &ffi_type_sint, &ffi_type_double, 
&ffi_type_uchar, &ffi_type_pointer, &ffi_type_pointer,
&ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer,
&ffi_type_pointer, &ffi_type_sshort, &ffi_type_schar,
#ifndef WINDOWS
&ffi_type_slong, 
#else
&ffi_type_sint,
#endif
&ffi_type_float};
  static const int types[] = {AT_VOID, AT_INT, AT_DOUBLE, AT_CHAR, AT_STRING, AT_PTR, AT_REFINT, 
     AT_REFDOUBLE, AT_REFCHAR, AT_CALLBACK, AT_SHORT, AT_BYTE, AT_LONG,
     AT_FLOAT};
  static const char *const typenames[] = 
    {"void", "int", "double", "char", "string", "pointer",
     "ref int", "ref double", "ref char", "callback", 
     "short", "byte", "long", "float", NULL};
  ffi_status status;
  ffi_abi abi;
  alien_Function *af = alien_checkfunction(L, 1);
  int i, j, ret_type;
  if(lua_istable(L, 2)) {
    lua_getfield(L, 2, "ret");
    ret_type = luaL_checkoption(L, -1, "int", typenames);
    af->ret_type = types[ret_type];
    af->ffi_ret_type = ffitypes[ret_type];
    lua_getfield(L, 2, "abi");
    abi = ffi_abis[luaL_checkoption(L, -1, "default", ffi_abi_names)];
    lua_pop(L, 2);
  } else {
    ret_type = luaL_checkoption(L, 2, "int", typenames);
    af->ret_type = types[ret_type];
    af->ffi_ret_type = ffitypes[ret_type];
    abi = FFI_DEFAULT_ABI;
  }
  if(af->params) { 
    free(af->params); free(af->ffi_params); 
    af->params = NULL; af->ffi_params = NULL;
  }
  if(lua_istable(L, 2)) {
    //af->nparams = lua_objlen(L, 2);
 af->nparams = lua_rawlen(L, 2);
  } else {
    af->nparams = lua_gettop(L) - 2;
  }
  if(af->nparams > 0) {
    af->ffi_params = (ffi_type **)malloc(sizeof(ffi_type *) * af->nparams);
    if(!af->ffi_params) luaL_error(L, "alien: out of memory");
    af->params = (alien_Type *)malloc(af->nparams * sizeof(alien_Type));
    if(!af->params) luaL_error(L, "alien: out of memory");
  }
  if(lua_istable(L, 2)) {
    for(i = 0, j = 1; i < af->nparams; i++, j++) {
      lua_rawgeti(L, 2, j);
      af->ffi_params[i] = ffitypes[luaL_checkoption(L, -1, "int", typenames)];
      af->params[i] = types[luaL_checkoption(L, -1, "int", typenames)];
      lua_pop(L, 1);
    }
  } else {
    for(i = 0, j = 3; i < af->nparams; i++, j++) {
      int type = luaL_checkoption(L, j, "int", typenames);
      af->ffi_params[i] = ffitypes[type];
      af->params[i] = types[type];
    }
  }
  status = ffi_prep_cif(&(af->cif), abi, af->nparams, 
af->ffi_ret_type,
af->ffi_params);
  if(status != FFI_OK)
    luaL_error(L, "alien: error in libffi preparation");
  return 0;
}


static int alien_function_tostring(lua_State *L) {
  alien_Function*af;
  af = alien_checkfunction(L, 1);
  lua_pushfstring(L, "alien function %s, library %s", af->name ? af->name : "anonymous",
  ((af->lib && af->lib->name) ? af->lib->name : "default"));
  return 1;
}


static int alien_function_call(lua_State *L) {
  int i, j, nargs, nparams;
  int iret; double dret; void *pret; long lret; float fret;
  int *refi_args = NULL;
  int nrefi, nrefd, nrefc;
  double *refd_args =NULL;
  char *refc_args = NULL;
  void **args = NULL;
  ffi_cif *cif;
  alien_Function *af = alien_checkfunction(L, 1);
  cif = &(af->cif);
  nparams = af->nparams;
  nargs = lua_gettop(L) - 1;
  if(nargs < nparams)
    luaL_error(L, "alien: too few arguments (function %s)", af->name ? 
      af->name : "anonymous");
  else if(nargs > nparams)
    luaL_error(L, "alien: too many arguments (function %s)", af->name ?
      af->name : "anonymous");
  for(i = 0, nrefi = 0, nrefd = 0, nrefc = 0; i < nparams; i++) {
    switch(af->params[i]) {
    case AT_REFINT: nrefi++; break;
    case AT_REFDOUBLE: nrefd++; break;
    case AT_REFCHAR: nrefc++; break;
    }
  }
  if(nrefi > 0) refi_args = (int*)ALLOCA(sizeof(int) * nrefi);
  if(nrefd > 0) refd_args = (double*)ALLOCA(sizeof(double) * nrefd);
  if(nrefc > 0) refc_args = (char*)ALLOCA(sizeof(char) * nrefc);
  if(nargs > 0) args = ALLOCA(sizeof(void*) * nargs);
  for(i = 0, j = 2; i < nparams; i++, j++) {
    void *arg;
    switch(af->params[i]) {
    case AT_SHORT:
      arg = ALLOCA(sizeof(short)); *((short*)arg) = (short)lua_tointeger(L, j); 
      args[i] = arg; break;
    case AT_LONG:
      arg = ALLOCA(sizeof(long)); *((long*)arg) = (long)lua_tointeger(L, j); 
      args[i] = arg; break;
    case AT_INT:
      arg = ALLOCA(sizeof(int)); *((int*)arg) = (int)lua_tointeger(L, j); 
      args[i] = arg; break;
    case AT_CHAR:
      arg = ALLOCA(sizeof(uchar)); *((uchar*)arg) = (uchar)lua_tointeger(L, j); 
      args[i] = arg; break;
    case AT_BYTE:
      arg = ALLOCA(sizeof(char)); *((char*)arg) = (signed char)lua_tointeger(L, j); 
      args[i] = arg; break;
    case AT_FLOAT:
      arg = ALLOCA(sizeof(float)); *((float*)arg) = (float)lua_tonumber(L, j); 
      args[i] = arg; break;
    case AT_DOUBLE:
      arg = ALLOCA(sizeof(double)); *((double*)arg) = (double)lua_tonumber(L, j); 
      args[i] = arg; break;
    case AT_STRING:
      arg = ALLOCA(sizeof(char*));
      if(lua_isuserdata(L, j))
*((char**)arg) = lua_isnil(L, j) ? NULL : lua_touserdata(L, j);
      else
*((const char**)arg) = lua_isnil(L, j) ? NULL : lua_tostring(L, j);
      args[i] = arg;
      break;
    case AT_CALLBACK: 
      arg = ALLOCA(sizeof(void*));
      *((void**)arg) = alien_checkcallback(L, j); 
      args[i] = arg;
      break;
    case AT_PTR:
      arg = ALLOCA(sizeof(char*));
      *((void**)arg) = lua_isnil(L, j) ? NULL : 
    (lua_isstring(L, j) ? (void*)lua_tostring(L, j) : 
     lua_touserdata(L, j));
      args[i] = arg;
      break;
    case AT_REFINT:
      *refi_args = (int)lua_tointeger(L, j);
      arg = ALLOCA(sizeof(int*));
      *((int**)arg) = refi_args;
      args[i] = arg; refi_args++; break;
      break;
    case AT_REFCHAR:
      *refc_args = (char)lua_tointeger(L, j);
      arg = ALLOCA(sizeof(char*));
      *((char**)arg) = refc_args;
      args[i] = arg; refc_args++; break;
      break;
    case AT_REFDOUBLE: 
      *refd_args = lua_tonumber(L, j);
      arg = ALLOCA(sizeof(double*));
      *((double**)arg) = refd_args;
      args[i] = arg; refd_args++; break;
      break;
    default: 
      luaL_error(L, "alien: parameter %i is of unknown type (function %s)", j, 
af->name ? af->name : "anonymous");
    }
  }
  pret = NULL;
  switch(af->ret_type) {
  case AT_VOID: ffi_call(cif, af->fn, NULL, args); lua_pushnil(L); break;
  case AT_SHORT: ffi_call(cif, af->fn, &iret, args); lua_pushnumber(L, (short)iret); break;
  case AT_LONG: 
    ffi_call(cif, af->fn, &lret, args); lua_pushnumber(L, lret); break;
  case AT_INT: ffi_call(cif, af->fn, &iret, args); lua_pushnumber(L, iret); break;
  case AT_CHAR: ffi_call(cif, af->fn, &iret, args); lua_pushnumber(L, (uchar)iret); break;
  case AT_BYTE: ffi_call(cif, af->fn, &iret, args); lua_pushnumber(L, (signed char)iret); break;
  case AT_FLOAT: ffi_call(cif, af->fn, &fret, args); lua_pushnumber(L, fret); break;
  case AT_DOUBLE: ffi_call(cif, af->fn, &dret, args); lua_pushnumber(L, dret); break;
  case AT_STRING: ffi_call(cif, af->fn, &pret, args);
 if (pret)
 {
 lua_pushstring(L, (const char *)pret);
 }
 else
 {
 lua_pushnil(L);
 }
 break;
  case AT_PTR: ffi_call(cif, af->fn, &pret, args); 
    (pret ? lua_pushlightuserdata(L, pret) : lua_pushnil(L)); break;
  default: 
    luaL_error(L, "alien: unknown return type (function %s)", af->name ?
      af->name : "anonymous");
  }
  refi_args -= nrefi; refd_args -= nrefd; refc_args -= nrefc;
  for(i = 0; i < nparams; i++) {
    switch(af->params[i]) {
    case AT_REFINT: lua_pushnumber(L, *refi_args); refi_args++; break;
    case AT_REFDOUBLE: lua_pushnumber(L, *refd_args); refd_args++; break;
    case AT_REFCHAR: lua_pushnumber(L, *refc_args); refc_args++; break;
    }
  }
  return 1 + nrefi + nrefc + nrefd;
}


static int alien_library_gc(lua_State *L) {
  alien_Library *al = alien_checklibrary(L, 1);
  if(al->lib) {
    alien_unload(al->lib);
    if(al->name) free(al->name);
  }
  return 0;
}


static int alien_function_gc(lua_State *L) {
  alien_Function *af = alien_checkfunction(L, 1);
  if(af->name) free(af->name);
  if(af->params) free(af->params);
  if(af->ffi_params) free(af->ffi_params);
  return 0;
}


static int alien_callback_gc(lua_State *L) {
  ffi_closure *ud = alien_checkcallback(L, 1);
  alien_Callback *ac = (alien_Callback *)ud->user_data;
  //lua_unref(ac->L, ac->fn_ref);
  luaL_unref(ac->L, LUA_REGISTRYINDEX, ac->fn_ref);
  if(ac->params) free(ac->params);
  if(ac->ffi_params) free(ac->ffi_params);
  free_closure(ud);
  return 0;
}


static int alien_register(lua_State *L) {
  const char *meta = luaL_checkstring(L, 1);
  luaL_getmetatable(L, meta);
  if(lua_isnil(L, -1))
    luaL_newmetatable(L, meta);
  return 1;
}


static int alien_pack(lua_State *L) {
  int i, top;
  alien_Wrap *ud;
  const char *meta = luaL_checkstring(L, 1);
  ud = (alien_Wrap*)lua_newuserdata(L, sizeof(alien_Wrap) * lua_gettop(L));
  top = lua_gettop(L);
  for(i = 2; i < top ; i++) {
    if(lua_isnil(L, i)) {
      ud[i - 2].tag = AT_PTR;
      ud[i - 2].val.p = NULL;
    }
    else if(lua_isuserdata(L, i)) {
      ud[i - 2].tag = AT_PTR;
      ud[i - 2].val.p = lua_touserdata(L, i);
    } else {
      ud[i - 2].tag = AT_INT;
      ud[i - 2].val.i = lua_tointeger(L, i);
    }
  }
  ud[lua_gettop(L) - 2].tag = AT_VOID;
  luaL_getmetatable(L, meta);
  lua_setmetatable(L, -2);
  return 1;
}


static int alien_unpack(lua_State *L) {
  int size, i;
  alien_Wrap *ud;
  const char *meta = luaL_checkstring(L, 1);
  ud = (alien_Wrap *)luaL_checkudata(L, 2, meta);
  luaL_argcheck(L, ud != NULL, 2, "userdata has wrong metatable");
  while(ud->tag != AT_VOID) {
    switch(ud->tag) {
    case AT_INT: lua_pushnumber(L, ud->val.i); break;
    case AT_PTR: ud->val.p ? lua_pushlightuserdata(L, ud->val.p) :
      lua_pushnil(L); break;
    default: luaL_error(L, "wrong type in wrapped value");
    }
    ud++;
  }
  return lua_gettop(L) - 2;
}


static int alien_repack(lua_State *L) {
  int size, i, top;
  alien_Wrap *ud;
  const char *meta = luaL_checkstring(L, 1);
  ud = (alien_Wrap *)luaL_checkudata(L, 2, meta);
  i = 3;
  top = lua_gettop(L);
  while(ud->tag != AT_VOID) {
    if(i > top || lua_isnil(L, i)) {
      ud->tag = AT_PTR;
      ud->val.p = NULL;
    }
    else if(lua_isuserdata(L, i)) {
      ud->tag = AT_PTR;
      ud->val.p = lua_touserdata(L, i);
    } else {
      ud->tag = AT_INT;
      ud->val.i = lua_tointeger(L, i);
    }
    ud++; i++;
  }
  return 0;
}


static int alien_buffer_new(lua_State *L) {
  const char *s; char *b;
  size_t size;
  if(lua_type(L, 1) == LUA_TSTRING) {
    s = lua_tolstring(L, 1, &size);
    size++;
  } else if(lua_type(L, 1) == LUA_TLIGHTUSERDATA) {
    luaL_getmetatable(L, ALIEN_BUFFER_META);
    lua_setmetatable(L, -2);
    return 1;
  } else {
    s = NULL;

    //size = luaL_optint(L, 1, BUFSIZ);
size = luaL_optinteger(L, 1, BUFSIZ);
  }
  b = (char *)lua_newuserdata(L, size);
  if(b) {
    if(s) {
      memcpy(b, s, size - 1);
      b[size - 1] = ‘\0‘;
    }
    luaL_getmetatable(L, ALIEN_BUFFER_META);
    lua_setmetatable(L, -2);
    return 1;
  } else {
    luaL_error(L, "cannot allocate buffer");
  }
  return 0;
}


static int alien_buffer_tostring(lua_State *L) {
  char *b;
  int size;
  b = alien_checkbuffer(L, 1);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = strlen(b);
  else
    size = luaL_checkinteger(L, 2);
  lua_pushlstring(L, b, size);
  return 1;
}


static int alien_buffer_len(lua_State *L) {
  char *b = alien_checkbuffer(L, 1);
  lua_pushinteger(L, strlen(b));
  return 1;
}


static int alien_buffer_topointer(lua_State *L) {
  char *b = alien_checkbuffer(L, 1);
  lua_pushlightuserdata(L, b);
  return 1;
}


static int alien_buffer_put(lua_State *L);


static int alien_buffer_get(lua_State *L) {
  static const void* funcs[] = {&alien_buffer_tostring,
&alien_buffer_topointer,
&alien_buffer_len,
&alien_buffer_get,
&alien_buffer_put};
  static const char *const funcnames[] = { "tostring", "topointer", "len", "get", "set", NULL };
  static const int types[] = {AT_VOID, AT_INT, AT_DOUBLE, AT_CHAR, AT_STRING, AT_PTR, AT_REFINT, 
     AT_REFDOUBLE, AT_REFCHAR, AT_CALLBACK, AT_SHORT, AT_BYTE, AT_LONG,
     AT_FLOAT};
  static const char *const typenames[] = 
    {"void", "int", "double", "char", "string", "pointer",
     "ref int", "ref double", "ref char", "callback", 
     "short", "byte", "long", "float", NULL};
  char *b = alien_checkbuffer(L, 1);
  if(lua_type(L, 2) == LUA_TSTRING) {
    lua_pushcfunction(L, 
     (lua_CFunction)funcs[luaL_checkoption(L, 2, "tostring", funcnames)]);
  } else {
    void *p;
    int offset = luaL_checkinteger(L, 2) - 1;
    int type = types[luaL_checkoption(L, 3, "char", typenames)];
    switch(type) {
    case AT_SHORT: lua_pushnumber(L, *((short*)(&b[offset]))); break;
    case AT_INT: lua_pushnumber(L, *((int*)(&b[offset]))); break;
    case AT_LONG: lua_pushnumber(L, *((long*)(&b[offset]))); break;
    case AT_BYTE: lua_pushnumber(L, (signed char)b[offset]); break;
    case AT_CHAR: lua_pushnumber(L, b[offset]); break;
    case AT_FLOAT: lua_pushnumber(L, *((float*)(&b[offset]))); break;
    case AT_DOUBLE: lua_pushnumber(L, *((double*)(&b[offset]))); break;
    case AT_STRING:
      p = *((void**)&b[offset]);
 if (p)
 {
 lua_pushstring(L, (char*)p);
 }
 else
 {
 lua_pushnil(L);
 }

      break;
    case AT_CALLBACK: 
      p = *((void**)&b[offset]);
      p ? alien_makefunction(L, NULL, p, NULL) : lua_pushnil(L);
      break; 
    case AT_PTR:
      p = *((void**)&b[offset]);
      p ? lua_pushlightuserdata(L, p) : lua_pushnil(L);
      break; 
    default: 
      luaL_error(L, "alien: unknown type in buffer:get");
    }
  }
  return 1;
}


static int alien_buffer_put(lua_State *L) {
  static const int types[] = {AT_VOID, AT_INT, AT_DOUBLE, AT_CHAR, AT_STRING, AT_PTR, AT_REFINT, 
     AT_REFDOUBLE, AT_REFCHAR, AT_CALLBACK, AT_SHORT, AT_BYTE, AT_LONG,
     AT_FLOAT};
  static const char *const typenames[] = 
    {"void", "int", "double", "char", "string", "pointer",
     "ref int", "ref double", "ref char", "callback", 
     "short", "byte", "long", "float", NULL};
  char *b = alien_checkbuffer(L, 1);
  int offset = luaL_checkinteger(L, 2) - 1;
  int type = types[luaL_checkoption(L, 4, "char", typenames)];
  switch(type) {
  case AT_SHORT: *((short*)(&b[offset])) = (short)lua_tointeger(L, 3); break;
  case AT_INT: *((int*)(&b[offset])) = (int)lua_tointeger(L, 3); break;
  case AT_LONG: *((long*)(&b[offset])) = (long)lua_tointeger(L, 3); break;
  case AT_BYTE: b[offset] = (signed char)lua_tointeger(L, 3); break;
  case AT_CHAR: b[offset] = (char)lua_tointeger(L, 3); break;
  case AT_FLOAT: *((float*)(&b[offset])) = (float)lua_tonumber(L, 3); break;
  case AT_DOUBLE: *((double*)(&b[offset])) = (double)lua_tonumber(L, 3); break;
  case AT_STRING: *((char**)(&b[offset])) = 
      (lua_isnil(L, 3) ? NULL : (char*)lua_tostring(L, 3)); break;
  case AT_CALLBACK: *((void**)(&b[offset])) = alien_checkcallback(L, 3); break;
  case AT_PTR: *((void**)(&b[offset])) = 
      (lua_isnil(L, 3) ? NULL : (lua_isuserdata(L, 3) ? lua_touserdata(L, 3) :
(void*)lua_tostring(L, 3))); break;
  default: 
    luaL_error(L, "alien: unknown type in buffer:put");
  }
  return 0;
}


static int alien_register_library_meta(lua_State *L) {
  luaL_newmetatable(L, ALIEN_LIBRARY_META);
  lua_pushliteral(L, "__gc");
  lua_pushcfunction(L, alien_library_gc);
  lua_settable(L, -3);
  lua_pushliteral(L, "__tostring");
  lua_pushcfunction(L, alien_library_tostring);
  lua_settable(L, -3);
  lua_pushliteral(L, "__index");
  lua_newtable(L);
  lua_pushcclosure(L, alien_library_get, 1);
  lua_settable(L, -3);
  lua_pop(L, 1);
  return 0;
}


static int alien_register_callback_meta(lua_State *L) {
  luaL_newmetatable(L, ALIEN_CALLBACK_META);
  lua_pushliteral(L, "__call");
  lua_pushcfunction(L, alien_function_call);
  lua_settable(L, -3);
  lua_pushliteral(L, "__gc");
  lua_pushcfunction(L, alien_callback_gc);
  lua_settable(L, -3);
  lua_pushliteral(L, "__tostring");
  lua_pushcfunction(L, alien_function_tostring);
  lua_settable(L, -3);
  lua_pop(L, 1);
  return 0;
}


static int alien_register_function_meta(lua_State *L) {
  luaL_newmetatable(L, ALIEN_FUNCTION_META);
  lua_pushliteral(L, "__index");
  lua_newtable(L);
  lua_pushliteral(L, "types");
  lua_pushcfunction(L, alien_function_types);
  lua_settable(L, -3);
  lua_settable(L, -3);
  lua_pushliteral(L, "__call");
  lua_pushcfunction(L, alien_function_call);
  lua_settable(L, -3);
  lua_pushliteral(L, "__gc");
  lua_pushcfunction(L, alien_function_gc);
  lua_settable(L, -3);
  lua_pushliteral(L, "__tostring");
  lua_pushcfunction(L, alien_function_tostring);
  lua_settable(L, -3);
  lua_pop(L, 1);
  return 0;
}


static int alien_register_buffer_meta(lua_State *L) {
  luaL_newmetatable(L, ALIEN_BUFFER_META);
  lua_pushliteral(L, "__index");
  lua_pushcfunction(L, alien_buffer_get);
  lua_settable(L, -3);
  lua_pushliteral(L, "__newindex");
  lua_pushcfunction(L, alien_buffer_put);
  lua_settable(L, -3);
  lua_pushliteral(L, "__tostring");
  lua_pushcfunction(L, alien_buffer_tostring);
  lua_settable(L, -3);
  lua_pop(L, 1);
  return 0;
}


static int alien_errno(lua_State *L) {
  lua_pushnumber(L, errno);
  return 1;
}


static int alien_udata2str(lua_State *L) {
  char *ud;
  int size;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  ud = (char *)lua_touserdata(L, 1);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = strlen(ud);
  else
    size = luaL_checkinteger(L, 2);
  lua_pushlstring(L, ud, size);
  return 1;
}


static int alien_udata2double(lua_State *L) {
  double *ud;
  int size, i;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = 1;
  else
    size = luaL_checkinteger(L, 2);
  ud = (double *)lua_touserdata(L, 1);
  for(i = 0; i < size; i++)
    lua_pushnumber(L, ud[i]);
  return size;
}


static int alien_udata2int(lua_State *L) {
  int *ud;
  int size, i;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = 1;
  else
    size = luaL_checkinteger(L, 2);
  ud = (int *)lua_touserdata(L, 1);
  for(i = 0; i < size; i++) {
    lua_pushnumber(L, ud[i]);
  }
  return size;
}


static int alien_udata2short(lua_State *L) {
  short *ud;
  int size, i;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = 1;
  else
    size = luaL_checkinteger(L, 2);
  ud = (short *)lua_touserdata(L, 1);
  for(i = 0; i < size; i++)
    lua_pushnumber(L, ud[i]);
  return size;
}


static int alien_udata2char(lua_State *L) {
  char *ud;
  int size, i;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = 1;
  else
    size = luaL_checkinteger(L, 2);
  ud = (char *)lua_touserdata(L, 1);
  for(i = 0; i < size; i++)
    lua_pushnumber(L, ud[i]);
  return size;
}


static int alien_udata2long(lua_State *L) {
  long *ud;
  int size, i;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = 1;
  else
    size = luaL_checkinteger(L, 2);
  ud = (long *)lua_touserdata(L, 1);
  for(i = 0; i < size; i++)
    lua_pushnumber(L, ud[i]);
  return size;
}


static int alien_udata2float(lua_State *L) {
  float *ud;
  int size, i;
  if(lua_isnil(L, 1)) {
    lua_pushnil(L);
    return 1;
  }
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  if(lua_gettop(L) < 2 || lua_isnil(L, 2))
    size = 1;
  else
    size = luaL_checkinteger(L, 2);
  ud = (float *)lua_touserdata(L, 1);
  for(i = 0; i < size; i++)
    lua_pushnumber(L, ud[i]);
  return size;
}


static int alien_isnull(lua_State *L) {
  void *ud;
  luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
  ud = lua_touserdata(L, 1);
  lua_pushboolean(L, ud == NULL);
  return 1;
}


static int alien_table_new(lua_State *L) {
  int narray, nhash;
  //narray = luaL_optint(L, 1, 0);
  //nhash = luaL_optint(L, 2, 0);


  narray = luaL_optinteger(L, 1, 0);
  nhash = luaL_optinteger(L, 2, 0);
  lua_createtable(L, narray, nhash);
  return 1;
}


static const struct luaL_Reg alienlib[] = {
  {"load", alien_get},
  {"align", alien_align},
  {"tag", alien_register},
  {"wrap", alien_pack},
  {"rewrap", alien_repack},
  {"unwrap", alien_unpack},
  {"errno", alien_errno},
  {"tostring", alien_udata2str},
  {"isnull", alien_isnull},
  {"sizeof", alien_sizeof},
  {"todouble", alien_udata2double},
  {"toint", alien_udata2int},
  {"tolong", alien_udata2long},
  {"tofloat", alien_udata2float},
  {"toshort", alien_udata2short},
  {"tochar", alien_udata2char},
  {"buffer", alien_buffer_new},
  {"callback", alien_callback_new},
  {"funcptr", alien_function_new},
  {"table", alien_table_new},
  {NULL, NULL},
};


static int alien_register_main(lua_State *L) {
  alien_Library *al;
  luaL_newlib(L, alienlib);
  lua_pushliteral(L, PLATFORM);
  lua_setfield(L, -2, "platform");
  al = (alien_Library *)lua_newuserdata(L, sizeof(alien_Library));
  al->lib = NULL;
  al->name = "default";
  luaL_getmetatable(L, ALIEN_LIBRARY_META);
  lua_setmetatable(L, -2);
  lua_setfield(L, -2, "default");
  return 1;
}


__declspec(dllexport) int luaopen_alien(lua_State *L) {
  alien_register_library_meta(L);
  alien_register_callback_meta(L);
  alien_register_function_meta(L);
  alien_register_buffer_meta(L);
  lua_getglobal(L, "alien");
  if(lua_isnil(L, -1)) {
    lua_newtable(L);
    lua_pushvalue(L, -1);
    lua_setglobal(L, "alien");
  }
  lua_newtable(L);
  lua_pushvalue(L, -1);
  lua_setfield(L, -3, "core");
  alien_register_main(L);
  return 1;
}

改写 alien core使其可以适配lua5.3