text: /******************************************************************************
  * Author: Alexey Melnichuk <mimir@newmail.ru>
  *
  * Copyright (C) 2014 Alexey Melnichuk <mimir@newmail.ru>
  *
  * Licensed according to the included 'LICENSE' document
  *
  * This file is part of lua-lcurl library.
  ******************************************************************************/
  
  #include "l52util.h"
  
  #include <memory.h>
  #include <string.h> /* for memset */
  #include <assert.h>
  
  #if LUA_VERSION_NUM >= 502 
  
  int luaL_typerror (lua_State *L, int narg, const char *tname) {
    const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
        luaL_typename(L, narg));
    return luaL_argerror(L, narg, msg);
  }
  
  #ifndef luaL_register
  
  void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l){
    if(libname) lua_newtable(L);
    luaL_setfuncs(L, l, 0);
  }
  
  #endif
  
  #else 
  
  void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup){
    luaL_checkstack(L, nup, "too many upvalues");
    for (; l->name != NULL; l++) {  /* fill the table with given functions */
      int i;
      for (i = 0; i < nup; i++)  /* copy upvalues to the top */
        lua_pushvalue(L, -nup);
      lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
      lua_setfield(L, -(nup + 2), l->name);
    }
    lua_pop(L, nup);  /* remove upvalues */
  }
  
  void lua_rawgetp(lua_State *L, int index, const void *p){
    index = lua_absindex(L, index);
    lua_pushlightuserdata(L, (void *)p);
    lua_rawget(L, index);
  }
  
  void lua_rawsetp (lua_State *L, int index, const void *p){
    index = lua_absindex(L, index);
    lua_pushlightuserdata(L, (void *)p);
    lua_insert(L, -2);
    lua_rawset(L, index);
  }
  
  #endif
  
  int lutil_newmetatablep (lua_State *L, const void *p) {
    lua_rawgetp(L, LUA_REGISTRYINDEX, p);
    if (!lua_isnil(L, -1))  /* name already in use? */
      return 0;  /* leave previous value on top, but return 0 */
    lua_pop(L, 1);
  
    lua_newtable(L);  /* create metatable */
    lua_pushvalue(L, -1); /* duplicate metatable to set*/
    lua_rawsetp(L, LUA_REGISTRYINDEX, p);
  
    return 1;
  }
  
  void lutil_getmetatablep (lua_State *L, const void *p) {
    lua_rawgetp(L, LUA_REGISTRYINDEX, p);
  }
  
  void lutil_setmetatablep (lua_State *L, const void *p) {
    lutil_getmetatablep(L, p);
    assert(lua_istable(L,-1));
    lua_setmetatable (L, -2);
  }
  
  int lutil_isudatap (lua_State *L, int ud, const void *p) {
    if (lua_isuserdata(L, ud)){
      if (lua_getmetatable(L, ud)) {           /* does it have a metatable? */
        int res;
        lutil_getmetatablep(L,p);              /* get correct metatable */
        res = lua_rawequal(L, -1, -2);         /* does it have the correct mt? */
        lua_pop(L, 2);                         /* remove both metatables */
        return res;
      }
    }
    return 0;
  }
  
  void *lutil_checkudatap (lua_State *L, int ud, const void *p) {
    void *up = lua_touserdata(L, ud);
    if (up != NULL) {                   /* value is a userdata? */
      if (lua_getmetatable(L, ud)) {    /* does it have a metatable? */
        lutil_getmetatablep(L,p);       /* get correct metatable */
        if (lua_rawequal(L, -1, -2)) {  /* does it have the correct mt? */
          lua_pop(L, 2);                /* remove both metatables */
          return up;
        }
      }
    }
    luaL_typerror(L, ud, (const char*)p);  /* else error */
    return NULL;              /* to avoid warnings */
  }
  
  int lutil_createmetap (lua_State *L, const void *p, const luaL_Reg *methods, int nup) {
    if (!lutil_newmetatablep(L, p)){
      lua_insert(L, -1 - nup);       /* move mt prior upvalues */
      return 0;
    }
  
    lua_insert(L, -1 - nup);         /* move mt prior upvalues */
    luaL_setfuncs (L, methods, nup); /* define methods */
    lua_pushliteral (L, "__index");  /* define metamethods */
    lua_pushvalue (L, -2);
    lua_settable (L, -3);
  
    return 1;
  }
  
  void *lutil_newudatap_impl(lua_State *L, size_t size, const void *p){
    void *obj = lua_newuserdata (L, size);
    memset(obj, 0, size);
    lutil_setmetatablep(L, p);
    return obj;
  }
  
  void lutil_pushint64(lua_State *L, int64_t v){
    if(sizeof(lua_Integer) >= sizeof(int64_t)){
      lua_pushinteger(L, (lua_Integer)v);
      return;
    }
    lua_pushnumber(L, (lua_Number)v);
  }
  
  int64_t lutil_checkint64(lua_State *L, int idx){
    if(sizeof(lua_Integer) >= sizeof(int64_t))
      return luaL_checkinteger(L, idx);
    return (int64_t)luaL_checknumber(L, idx);
  }
  
  int64_t lutil_optint64(lua_State *L, int idx, int64_t v){
    if(sizeof(lua_Integer) >= sizeof(int64_t))
      return luaL_optinteger(L, idx, v);
    return (int64_t)luaL_optnumber(L, idx, v);
  }
  
  void lutil_pushnvalues(lua_State *L, int n){
    for(;n;--n) lua_pushvalue(L, -n);
  }
  
  int lutil_is_null(lua_State *L, int i){
    return lua_islightuserdata(L, i) && 0 == lua_touserdata(L, i);
  }
  
  void lutil_push_null(lua_State *L){
    lua_pushlightuserdata(L, (void*)0);
  }
  