#include "lcurl.h" #include "lceasy.h" #include "lcerror.h" #include "lcutils.h" #include "lchttppost.h" #include "lcshare.h" static const char *LCURL_ERROR_TAG = "LCURL_ERROR_TAG"; #define LCURL_EASY_NAME LCURL_PREFIX" Easy" static const char *LCURL_EASY = LCURL_EASY_NAME; //{ int lcurl_easy_create(lua_State *L, int error_mode){ lcurl_easy_t *p = lutil_newudatap(L, lcurl_easy_t, LCURL_EASY); int i; p->curl = curl_easy_init(); p->err_mode = error_mode; if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_FAILED_INIT); p->L = L; p->storage = lcurl_storage_init(L); p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF; p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF; p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF; p->pr.cb_ref = p->pr.ud_ref = LUA_NOREF; p->rbuffer.ref = LUA_NOREF; for(i = 0; i < LCURL_LIST_COUNT; ++i){ p->lists[i] = LUA_NOREF; } return 1; } lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i){ lcurl_easy_t *p = (lcurl_easy_t *)lutil_checkudatap (L, i, LCURL_EASY); luaL_argcheck (L, p != NULL, 1, LCURL_EASY_NAME" expected"); return p; } static int lcurl_easy_cleanup(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); int i; if(p->curl){ curl_easy_cleanup(p->curl); p->curl = NULL; } if(p->storage != LUA_NOREF){ p->storage = lcurl_storage_free(L, p->storage); } luaL_unref(L, LCURL_LUA_REGISTRY, p->wr.cb_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->wr.ud_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->rd.cb_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->rd.ud_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->pr.cb_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->pr.ud_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.cb_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.ud_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF; p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF; p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF; p->pr.cb_ref = p->pr.ud_ref = LUA_NOREF; p->rbuffer.ref = LUA_NOREF; for(i = 0; i < LCURL_LIST_COUNT; ++i){ luaL_unref(L, LCURL_LUA_REGISTRY, p->lists[i]); p->lists[i] = LUA_NOREF; } return 0; } static int lcurl_easy_perform(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); CURLcode code; int top = 1; lua_settop(L, top); assert(p->rbuffer.ref == LUA_NOREF); code = curl_easy_perform(p->curl); if(p->rbuffer.ref != LUA_NOREF){ luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); p->rbuffer.ref = LUA_NOREF; } if(code == CURLE_OK){ lua_settop(L, 1); return 1; } if((lua_gettop(L) > top)&&(lua_touserdata(L, top + 1) == LCURL_ERROR_TAG)){ return lua_error(L); } if(code == CURLE_WRITE_ERROR){ if(lua_gettop(L) > top){ return lua_gettop(L) - top; } } if(code == CURLE_ABORTED_BY_CALLBACK){ if(lua_gettop(L) > top){ return lua_gettop(L) - top; } } return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } static int lcurl_easy_escape(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); size_t data_size; const char *data = luaL_checklstring(L, 2, &data_size); const char *ret = curl_easy_escape(p->curl, data, (int)data_size); if(!ret){ lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_OUT_OF_MEMORY); } lua_pushstring(L, ret); curl_free((char*)ret); return 1; } static int lcurl_easy_unescape(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); size_t data_size; const char *data = luaL_checklstring(L, 2, &data_size); int ret_size; const char *ret = curl_easy_unescape(p->curl, data, (int)data_size, &ret_size); if(!ret){ lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_OUT_OF_MEMORY); } lua_pushlstring(L, ret, ret_size); curl_free((char*)ret); return 1; } static int lcurl_easy_reset(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); curl_easy_reset(p->curl); lua_settop(L, 1); if(p->storage != LUA_NOREF){ lcurl_storage_free(L, p->storage); p->storage = lcurl_storage_init(L); } return 1; } //{ OPTIONS static int lcurl_opt_set_long_(lua_State *L, int opt){ lcurl_easy_t *p = lcurl_geteasy(L); long val; CURLcode code; if(lua_isboolean(L, 2)) val = lua_toboolean(L, 2); else{ luaL_argcheck(L, lua_type(L, 2) == LUA_TNUMBER, 2, "number or boolean expected"); val = luaL_checklong(L, 2); } code = curl_easy_setopt(p->curl, opt, val); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lua_settop(L, 1); return 1; } static int lcurl_opt_set_string_(lua_State *L, int opt, int store){ lcurl_easy_t *p = lcurl_geteasy(L); CURLcode code; luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING, 2, "string expected"); code = curl_easy_setopt(p->curl, opt, lua_tostring(L, 2)); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } if(store)lcurl_storage_preserve_value(L, p->storage, 2); lua_settop(L, 1); return 1; } static int lcurl_opt_set_slist_(lua_State *L, int opt, int list_no){ lcurl_easy_t *p = lcurl_geteasy(L); struct curl_slist *list = lcurl_util_to_slist(L, 2); CURLcode code; int ref = p->lists[list_no]; luaL_argcheck(L, list, 2, "array expected"); if(ref != LUA_NOREF){ struct curl_slist *tmp = lcurl_storage_remove_slist(L, p->storage, ref); curl_slist_free_all(tmp); p->lists[list_no] = LUA_NOREF; } code = curl_easy_setopt(p->curl, opt, list); if(code != CURLE_OK){ curl_slist_free_all(list); return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } p->lists[list_no] = lcurl_storage_preserve_slist(L, p->storage, list); lua_settop(L, 1); return 1; } #define LCURL_STR_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\ return lcurl_opt_set_string_(L, CURLOPT_##N, (S)); \ } #define LCURL_LST_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\ return lcurl_opt_set_slist_(L, CURLOPT_##N, LCURL_##N##_LIST);\ } #define LCURL_LNG_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\ return lcurl_opt_set_long_(L, CURLOPT_##N);\ } #define OPT_ENTRY(L, N, T, S) LCURL_##T##_OPT(N, S) #include "lcopteasy.h" #undef OPT_ENTRY static int lcurl_easy_set_POSTFIELDS(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); size_t len; const char *val = luaL_checklstring(L, 2, &len); CURLcode code; if(lua_isnumber(L, 3)){ size_t n = (size_t)lua_tonumber(L, 3); luaL_argcheck(L, len <= n, 3, "data length too big"); len = n; } code = curl_easy_setopt(p->curl, CURLOPT_POSTFIELDS, val); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lcurl_storage_preserve_value(L, p->storage, 2); code = curl_easy_setopt(p->curl, CURLOPT_POSTFIELDSIZE, (long)len); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lua_settop(L, 1); return 1; } #undef LCURL_STR_OPT #undef LCURL_LST_OPT #undef LCURL_LNG_OPT static int lcurl_easy_set_HTTPPOST(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); lcurl_hpost_t *post = lcurl_gethpost_at(L, 2); CURLcode code = curl_easy_setopt(p->curl, CURLOPT_HTTPPOST, post->post); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lcurl_storage_preserve_value(L, p->storage, 2); lua_settop(L, 1); return 1; } static int lcurl_easy_set_SHARE(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); lcurl_share_t *sh = lcurl_getshare_at(L, 2); CURLcode code = curl_easy_setopt(p->curl, CURLOPT_SHARE, sh->curl); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lcurl_storage_preserve_value(L, p->storage, 2); lua_settop(L, 1); return 1; } //} //{ info static int lcurl_info_get_long_(lua_State *L, int opt){ lcurl_easy_t *p = lcurl_geteasy(L); long val; CURLcode code; code = curl_easy_getinfo(p->curl, opt, &val); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lua_pushnumber(L, val); return 1; } static int lcurl_info_get_double_(lua_State *L, int opt){ lcurl_easy_t *p = lcurl_geteasy(L); double val; CURLcode code; code = curl_easy_getinfo(p->curl, opt, &val); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lua_pushnumber(L, val); return 1; } static int lcurl_info_get_string_(lua_State *L, int opt){ lcurl_easy_t *p = lcurl_geteasy(L); char *val; CURLcode code; code = curl_easy_getinfo(p->curl, opt, &val); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lua_pushstring(L, val); return 1; } static int lcurl_info_get_slist_(lua_State *L, int opt){ lcurl_easy_t *p = lcurl_geteasy(L); struct curl_slist *val; CURLcode code; code = curl_easy_getinfo(p->curl, opt, &val); if(code != CURLE_OK){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); } lcurl_util_slist_to_table(L, val); curl_slist_free_all(val); return 1; } #define LCURL_STR_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\ return lcurl_info_get_string_(L, CURLINFO_##N); \ } #define LCURL_LST_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\ return lcurl_info_get_slist_(L, CURLINFO_##N);\ } #define LCURL_LNG_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\ return lcurl_info_get_long_(L, CURLINFO_##N);\ } #define LCURL_DBL_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\ return lcurl_info_get_double_(L, CURLINFO_##N);\ } #define OPT_ENTRY(L, N, T, S) LCURL_##T##_INFO(N, S) #include "lcinfoeasy.h" #undef OPT_ENTRY #undef LCURL_STR_INFO #undef LCURL_LST_INFO #undef LCURL_LNG_INFO #undef LCURL_DBL_INFO //} //{ CallBack static int lcurl_easy_set_callback(lua_State *L, lcurl_easy_t *p, lcurl_callback_t *c, int OPT_CB, int OPT_UD, const char *method, void *func ) { if(c->ud_ref != LUA_NOREF){ luaL_unref(L, LCURL_LUA_REGISTRY, c->ud_ref); c->ud_ref = LUA_NOREF; } if(c->cb_ref != LUA_NOREF){ luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref); c->cb_ref = LUA_NOREF; } if(lua_gettop(L) >= 3){// function + context lua_settop(L, 3); luaL_argcheck(L, !lua_isnil(L, 2), 2, "no function present"); c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY); c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY); curl_easy_setopt(p->curl, OPT_UD, p); curl_easy_setopt(p->curl, OPT_CB, func); assert(1 == lua_gettop(L)); return 1; } lua_settop(L, 2); if(lua_isnoneornil(L, 2)){ lua_pop(L, 1); assert(1 == lua_gettop(L)); curl_easy_setopt(p->curl, OPT_UD, 0); curl_easy_setopt(p->curl, OPT_CB, 0); return 1; } if(lua_isfunction(L, 2)){ c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY); assert(1 == lua_gettop(L)); curl_easy_setopt(p->curl, OPT_UD, p); curl_easy_setopt(p->curl, OPT_CB, func); return 1; } if(lua_isuserdata(L, 2) || lua_istable(L, 2)){ lua_getfield(L, 2, method); luaL_argcheck(L, lua_isfunction(L, -1), 2, "method not found in object"); c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY); c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY); curl_easy_setopt(p->curl, OPT_UD, p); curl_easy_setopt(p->curl, OPT_CB, func); assert(1 == lua_gettop(L)); return 1; } lua_pushliteral(L, "invalid object type"); return lua_error(L); } static int lcurl_write_callback_(lua_State*L, lcurl_easy_t *p, lcurl_callback_t *c, char *ptr, size_t size, size_t nmemb ){ size_t ret = size * nmemb; int top = lua_gettop(L); int n = lcurl_util_push_cb(L, c); lua_pushlstring(L, ptr, ret); if(lua_pcall(L, n, LUA_MULTRET, 0)){ assert(lua_gettop(L) >= top); lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG); lua_insert(L, top+1); return 0; } if(lua_gettop(L) > top){ if(lua_isnil(L, top + 1)) return 0; if(lua_isboolean(L, top + 1)){ if(!lua_toboolean(L, top + 1)) ret = 0; } else ret = (size_t)lua_tonumber(L, top + 1); } lua_settop(L, top); return ret; } //{ Writer static int lcurl_write_callback(char *ptr, size_t size, size_t nmemb, void *arg){ lcurl_easy_t *p = arg; return lcurl_write_callback_(p->L, p, &p->wr, ptr, size, nmemb); } static int lcurl_easy_set_WRITEFUNCTION(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); return lcurl_easy_set_callback(L, p, &p->wr, CURLOPT_WRITEFUNCTION, CURLOPT_WRITEDATA, "write", lcurl_write_callback ); } //} //{ Reader static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *arg){ lcurl_easy_t *p = arg; lua_State *L = p->L; const char *data; size_t data_size; size_t ret = size * nitems; int n, top = lua_gettop(L); if(p->rbuffer.ref != LUA_NOREF){ lua_rawgeti(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); data = luaL_checklstring(L, -1, &data_size); lua_pop(L, 1); data = data + p->rbuffer.off; data_size -= p->rbuffer.off; if(data_size > ret){ data_size = ret; memcpy(buffer, data, data_size); p->rbuffer.off += data_size; } else{ memcpy(buffer, data, data_size); luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); p->rbuffer.ref = LUA_NOREF; } lua_settop(L, top); return data_size; } // buffer is clean assert(p->rbuffer.ref == LUA_NOREF); n = lcurl_util_push_cb(L, &p->rd); lua_pushnumber(L, ret); if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT; if(lua_isnoneornil(L, top + 1)){ if(lua_gettop(L) <= (top + 1))return 0; return CURL_READFUNC_ABORT; } data = lua_tolstring(L, -1, &data_size); if(!data) return CURL_READFUNC_ABORT; if(data_size > ret){ data_size = ret; p->rbuffer.ref = luaL_ref(L, LCURL_LUA_REGISTRY); p->rbuffer.off = data_size; } memcpy(buffer, data, data_size); lua_settop(L, top); return data_size; } static int lcurl_easy_set_READFUNCTION(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); return lcurl_easy_set_callback(L, p, &p->rd, CURLOPT_READFUNCTION, CURLOPT_READDATA, "read", lcurl_read_callback ); } //} //{ Header static int lcurl_header_callback(char *ptr, size_t size, size_t nmemb, void *arg){ lcurl_easy_t *p = arg; return lcurl_write_callback_(p->L, p, &p->hd, ptr, size, nmemb); } static int lcurl_easy_set_HEADERFUNCTION(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); return lcurl_easy_set_callback(L, p, &p->hd, CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA, "header", lcurl_header_callback ); } //} //{ Progress static int lcurl_xferinfo_callback(void *arg, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { lcurl_easy_t *p = arg; lua_State *L = p->L; int ret = 0; int top = lua_gettop(L); int n = lcurl_util_push_cb(L, &p->pr); lua_pushnumber( L, (lua_Number)dltotal ); lua_pushnumber( L, (lua_Number)dlnow ); lua_pushnumber( L, (lua_Number)ultotal ); lua_pushnumber( L, (lua_Number)ulnow ); if(lua_pcall(L, n+3, LUA_MULTRET, 0)){ assert(lua_gettop(L) >= top); lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG); lua_insert(L, top+1); return 0; } if(lua_gettop(L) > top){ if(lua_isnil(L, top + 1)) return 1; if(lua_isboolean(L, top + 1)) ret = lua_toboolean(L, top + 1)?0:1; else ret = (size_t)lua_tonumber(L, top + 1); } lua_settop(L, top); return ret; } static int lcurl_progress_callback(void *arg, double dltotal, double dlnow, double ultotal, double ulnow) { return lcurl_xferinfo_callback(arg, (curl_off_t)dltotal, (curl_off_t)dlnow, (curl_off_t)ultotal, (curl_off_t)ulnow ); } static int lcurl_easy_set_PROGRESSFUNCTION(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); int n = lcurl_easy_set_callback(L, p, &p->pr, CURLOPT_PROGRESSFUNCTION, CURLOPT_PROGRESSDATA, "progress", lcurl_progress_callback ); #if LCURL_CURL_VER_GE(7,32,0) if(p->pr.cb_ref != LUA_NOREF){ CURLcode code; code = curl_easy_setopt(p->curl, CURLOPT_XFERINFOFUNCTION, lcurl_xferinfo_callback); code = curl_easy_setopt(p->curl, CURLOPT_XFERINFODATA, p); } #endif return n; } //} //} static int lcurl_easy_setopt(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); int opt = luaL_checklong(L, 2); lua_remove(L, 2); #define OPT_ENTRY(l, N, T, S) case CURLOPT_##N: return lcurl_easy_set_##N(L); switch(opt){ #include "lcopteasy.h" OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) OPT_ENTRY(httppost, HTTPPOST, TTT, 0) OPT_ENTRY(share, SHARE, TTT, 0) OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0) } #undef OPT_ENTRY return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, #if LCURL_CURL_VER_GE(7,21,5) CURLE_UNKNOWN_OPTION #else CURLE_UNKNOWN_TELNET_OPTION #endif ); } static int lcurl_easy_getinfo(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); int opt = luaL_checklong(L, 2); lua_remove(L, 2); #define OPT_ENTRY(l, N, T, S) case CURLINFO_##N: return lcurl_easy_get_##N(L); switch(opt){ #include "lcinfoeasy.h" } #undef OPT_ENTRY return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_UNKNOWN_OPTION); } //} static const struct luaL_Reg lcurl_easy_methods[] = { #define OPT_ENTRY(L, N, T, S) { "setopt_"#L, lcurl_easy_set_##N }, #include "lcopteasy.h" OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) OPT_ENTRY(httppost, HTTPPOST, TTT, 0) OPT_ENTRY(share, SHARE, TTT, 0) OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0) #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S) { "getinfo_"#L, lcurl_easy_get_##N }, #include "lcinfoeasy.h" #undef OPT_ENTRY { "reset", lcurl_easy_reset }, { "setopt", lcurl_easy_setopt }, { "getinfo", lcurl_easy_getinfo }, { "escape", lcurl_easy_escape }, { "unescape", lcurl_easy_unescape }, { "perform", lcurl_easy_perform }, { "close", lcurl_easy_cleanup }, { "__gc", lcurl_easy_cleanup }, {NULL,NULL} }; static const lcurl_const_t lcurl_easy_opt[] = { #define OPT_ENTRY(L, N, T, S) { "OPT_"#N, CURLOPT_##N }, #define FLG_ENTRY(N) { #N, CURL_##N }, #include "lcopteasy.h" OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) OPT_ENTRY(httppost, HTTPPOST, TTT, 0) OPT_ENTRY(share, SHARE, TTT, 0) OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0) #undef OPT_ENTRY #undef FLG_ENTRY #define OPT_ENTRY(L, N, T, S) { "INFO_"#N, CURLINFO_##N }, #include "lcinfoeasy.h" #undef OPT_ENTRY {NULL, 0} }; void lcurl_easy_initlib(lua_State *L, int nup){ if(!lutil_createmetap(L, LCURL_EASY, lcurl_easy_methods, nup)) lua_pop(L, nup); lua_pop(L, 1); lcurl_util_set_const(L, lcurl_easy_opt); }