/** * walk through the content array * * content = { "<pre>", { file = "/content" } , "</pre>" } * * header["Content-Type"] = "text/html" * * return 200 */ static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) { UNUSED(p); /** * get the environment of the function */ assert(lua_isfunction(L, -1)); lua_getfenv(L, -1); /* -1 is the function */ lua_getfield(L, -1, "lighty"); /* lighty.* from the env */ assert(lua_istable(L, -1)); lua_getfield(L, -1, "content"); /* lighty.content */ if (lua_istable(L, -1)) { int i; /* header is found, and is a table */ for (i = 1; ; i++) { lua_rawgeti(L, -1, i); /* -1 is the value and should be the value ... aka a table */ if (lua_isstring(L, -1)) { size_t s_len = 0; const char *s = lua_tolstring(L, -1, &s_len); chunkqueue_append_mem(con->send, s, s_len); } else if (lua_istable(L, -1)) { lua_getfield(L, -1, "filename"); lua_getfield(L, -2, "length"); lua_getfield(L, -3, "offset"); if (lua_isstring(L, -3)) { /* filename has to be a string */ buffer *fn = buffer_init(); stat_cache_entry *sce; buffer_copy_string(fn, lua_tostring(L, -3)); if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) { off_t off = 0; off_t len = 0; if (lua_isnumber(L, -1)) { off = lua_tonumber(L, -1); } if (lua_isnumber(L, -2)) { len = lua_tonumber(L, -2); } else { len = sce->st.st_size; } if (off < 0) { return luaL_error(L, "offset for '%s' is negative", fn->ptr); } if (len < off) { return luaL_error(L, "offset > length for '%s'", fn->ptr); } chunkqueue_append_file(con->send, fn, off, len - off); } buffer_free(fn); } else { lua_pop(L, 3 + 2); /* correct the stack */ return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i); } lua_pop(L, 3); } else if (lua_isnil(L, -1)) { /* oops, end of list */ lua_pop(L, 1); break; } else { lua_pop(L, 4); return luaL_error(L, "content[%d] is neither a string nor a table: ", i); } lua_pop(L, 1); /* pop the content[...] table */ } } else { return luaL_error(L, "lighty.content has to be a table"); } lua_pop(L, 1); /* pop the header-table */ lua_pop(L, 1); /* pop the lighty-table */ lua_pop(L, 1); /* php the function env */ return 0; }
static int log_wrapper(ngx_tcp_session_t *s, const char *ident, ngx_uint_t level, lua_State *L) { u_char *buf; u_char *p, *q; ngx_str_t name; int nargs, i; size_t size, len; size_t src_len = 0; int type; const char *msg; lua_Debug ar; ngx_buf_t *b; if (level > s->connection->log->log_level) { return 0; } dd("log level: %d", (int)level); #if 1 /* add debug info */ lua_getstack(L, 1, &ar); lua_getinfo(L, "Snl", &ar); /* get the basename of the Lua source file path, stored in q */ name.data = (u_char *) ar.short_src; if (name.data == NULL) { name.len = 0; } else { p = name.data; while (*p != '\0') { if (*p == '/' || *p == '\\') { name.data = p + 1; } p++; } name.len = p - name.data; } #endif nargs = lua_gettop(L); size = name.len + NGX_INT_T_LEN + sizeof(":: ") - 1; if (*ar.namewhat != '\0' && *ar.what == 'L') { src_len = ngx_strlen(ar.name); size += src_len + sizeof("(): ") - 1; } for (i = 1; i <= nargs; i++) { type = lua_type(L, i); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: lua_tolstring(L, i, &len); size += len; break; case LUA_TNIL: size += sizeof("nil") - 1; break; case LUA_TBOOLEAN: if (lua_toboolean(L, i)) { size += sizeof("true") - 1; } else { size += sizeof("false") - 1; } break; case LUA_TLIGHTUSERDATA: if (lua_touserdata(L, i) == NULL) { size += sizeof("null") - 1; break; } continue; default: msg = lua_pushfstring(L, "string, number, boolean, or nil " "expected, got %s", lua_typename(L, type)); return luaL_argerror(L, i, msg); } } //buf = lua_newuserdata(L, size + 1); b = ngx_create_temp_buf(s->pool, size + 1); buf = (u_char*)b->pos; p = ngx_copy(buf, name.data, name.len); *p++ = ':'; p = ngx_snprintf(p, NGX_INT_T_LEN, "%d", ar.currentline ? ar.currentline : ar.linedefined); *p++ = ':'; *p++ = ' '; if (*ar.namewhat != '\0' && *ar.what == 'L') { p = ngx_copy(p, ar.name, src_len); *p++ = '('; *p++ = ')'; *p++ = ':'; *p++ = ' '; } for (i = 1; i <= nargs; i++) { type = lua_type(L, i); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: q = (u_char *) lua_tolstring(L, i, &len); p = ngx_copy(p, q, len); break; case LUA_TNIL: *p++ = 'n'; *p++ = 'i'; *p++ = 'l'; break; case LUA_TBOOLEAN: if (lua_toboolean(L, i)) { *p++ = 't'; *p++ = 'r'; *p++ = 'u'; *p++ = 'e'; } else { *p++ = 'f'; *p++ = 'a'; *p++ = 'l'; *p++ = 's'; *p++ = 'e'; } break; case LUA_TLIGHTUSERDATA: *p++ = 'n'; *p++ = 'u'; *p++ = 'l'; *p++ = 'l'; break; default: return luaL_error(L, "impossible to reach here"); } } *p++ = '\0'; if (p - buf > (off_t) (size + 1)) { return luaL_error(L, "buffer error: %d > %d", (int) (p - buf), (int) (size + 1)); } ngx_log_error(level, s->connection->log, 0, "%s%s", ident, buf); return 0; }
/* unsigned address string address integer type integer session string message lightuserdata message_ptr integer len */ static int _send(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); int addr_type = lua_type(L,1); uint32_t dest = 0; switch(addr_type) { case LUA_TNUMBER: dest = lua_tounsigned(L,1); break; case LUA_TSTRING: { const char * addrname = lua_tostring(L,1); if (addrname[0] == '.' || addrname[0] == ':') { dest = skynet_queryname(context, addrname); if (dest == 0) { luaL_error(L, "Invalid name %s", addrname); } } else if ('0' <= addrname[0] && addrname[0] <= '9') { luaL_error(L, "Invalid name %s: must not start with a digit", addrname); } else { return _sendname(L, context, addrname); } break; } default: return luaL_error(L, "address must be number or string, got %s",lua_typename(L,addr_type)); } int type = luaL_checkinteger(L, 2); int session = 0; if (lua_isnil(L,3)) { type |= PTYPE_TAG_ALLOCSESSION; } else { session = luaL_checkinteger(L,3); } int mtype = lua_type(L,4); switch (mtype) { case LUA_TSTRING: { size_t len = 0; void * msg = (void *)lua_tolstring(L,4,&len); if (len == 0) { msg = NULL; } session = skynet_send(context, 0, dest, type, session , msg, len); break; } case LUA_TLIGHTUSERDATA: { void * msg = lua_touserdata(L,4); int size = luaL_checkinteger(L,5); session = skynet_send(context, 0, dest, type | PTYPE_TAG_DONTCOPY, session, msg, size); break; } default: luaL_error(L, "skynet.send invalid param %s", lua_type(L,4)); } if (session < 0) { luaL_error(L, "skynet.send session (%d) < 0", session); } lua_pushinteger(L,session); return 1; }
static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { lua_CFunction cfunc= lua_tocfunction( L,i ); unsigned n; ASSERT_L( L2_cache_i != 0 ); STACK_GROW(L,2); STACK_CHECK(L) if (!cfunc) { // Lua function luaL_Buffer b; const char *s; size_t sz; int tmp; const char *name= NULL; #if 0 // "To get information about a function you push it onto the // stack and start the what string with the character '>'." // { lua_Debug ar; lua_pushvalue( L, i ); lua_getinfo(L, ">n", &ar); // fills 'name' and 'namewhat', pops function name= ar.namewhat; fprintf( stderr, "NAME: %s\n", name ); // just gives NULL } #endif // 'lua_dump()' needs the function at top of stack // if (i!=-1) lua_pushvalue( L, i ); luaL_buffinit(L,&b); tmp= lua_dump(L, buf_writer, &b); ASSERT_L(tmp==0); // // "value returned is the error code returned by the last call // to the writer" (and we only return 0) luaL_pushresult(&b); // pushes dumped string on 'L' s= lua_tolstring(L,-1,&sz); ASSERT_L( s && sz ); if (i!=-1) lua_remove( L, -2 ); // Note: Line numbers seem to be taken precisely from the // original function. 'name' is not used since the chunk // is precompiled (it seems...). // // TBD: Can we get the function's original name through, as well? // if (luaL_loadbuffer(L2, s, sz, name) != 0) { // chunk is precompiled so only LUA_ERRMEM can happen // "Otherwise, it pushes an error message" // STACK_GROW( L,1 ); luaL_error( L, "%s", lua_tostring(L2,-1) ); } lua_pop(L,1); // remove the dumped string STACK_MID(L,0) }
ItemStack read_item(lua_State* L, int index,Server* srv) { if(index < 0) index = lua_gettop(L) + 1 + index; if(lua_isnil(L, index)) { return ItemStack(); } else if(lua_isuserdata(L, index)) { // Convert from LuaItemStack LuaItemStack *o = LuaItemStack::checkobject(L, index); return o->getItem(); } else if(lua_isstring(L, index)) { // Convert from itemstring std::string itemstring = lua_tostring(L, index); IItemDefManager *idef = srv->idef(); try { ItemStack item; item.deSerialize(itemstring, idef); return item; } catch(SerializationError &e) { warningstream<<"unable to create item from itemstring" <<": "<<itemstring<<std::endl; return ItemStack(); } } else if(lua_istable(L, index)) { // Convert from table IItemDefManager *idef = srv->idef(); std::string name = getstringfield_default(L, index, "name", ""); int count = getintfield_default(L, index, "count", 1); int wear = getintfield_default(L, index, "wear", 0); ItemStack istack(name, count, wear, idef); lua_getfield(L, index, "metadata"); // Support old metadata format by checking type int fieldstable = lua_gettop(L); if (lua_istable(L, fieldstable)) { lua_pushnil(L); while (lua_next(L, fieldstable) != 0) { // key at index -2 and value at index -1 std::string key = lua_tostring(L, -2); size_t value_len; const char *value_cs = lua_tolstring(L, -1, &value_len); std::string value(value_cs, value_len); istack.metadata.setString(name, value); lua_pop(L, 1); // removes value, keeps key for next iteration } } else { // BACKWARDS COMPATIBLITY std::string value = getstringfield_default(L, index, "metadata", ""); istack.metadata.setString("", value); } lua_getfield(L, index, "meta"); fieldstable = lua_gettop(L); if (lua_istable(L, fieldstable)) { lua_pushnil(L); while (lua_next(L, fieldstable) != 0) { // key at index -2 and value at index -1 std::string key = lua_tostring(L, -2); size_t value_len; const char *value_cs = lua_tolstring(L, -1, &value_len); std::string value(value_cs, value_len); istack.metadata.setString(name, value); lua_pop(L, 1); // removes value, keeps key for next iteration } } return istack; } else { throw LuaError("Expecting itemstack, itemstring, table or nil"); } }
/* * Arguments: membuf_udata, offset (number), value */ static int mem_newindex (lua_State *L) { struct membuf *mb = checkudata(L, 1, MEM_TYPENAME); const int off = lua_tointeger(L, 2); const int type = memtype(mb); char *ptr = mb->data + memlen(type, off); switch (lua_type(L, 3)) { case LUA_TNUMBER: { lua_Number num = lua_tonumber(L, 3); switch (type) { case MEM_TCHAR: *((char *) ptr) = (char) num; break; case MEM_TUCHAR: *((unsigned char *) ptr) = (unsigned char) num; break; case MEM_TSHORT: *((short *) ptr) = (short) num; break; case MEM_TUSHORT: *((unsigned short *) ptr) = (unsigned short) num; break; case MEM_TINT: *((int *) ptr) = (int) num; break; case MEM_TUINT: *((unsigned int *) ptr) = (unsigned int) num; break; case MEM_TLONG: *((long *) ptr) = (long) num; break; case MEM_TULONG: *((unsigned long *) ptr) = (unsigned long) num; break; case MEM_TFLOAT: *((float *) ptr) = (float) num; break; case MEM_TDOUBLE: *((double *) ptr) = (double) num; break; case MEM_TNUMBER: *((lua_Number *) ptr) = num; break; case MEM_TBITSTRING: luaL_argerror(L, 3, "boolean expected"); break; } } break; case LUA_TBOOLEAN: if (type != MEM_TBITSTRING) luaL_argerror(L, 1, "bitstring expected"); else { const int bit = 1 << (off & 7); --ptr; /* correct address */ if (lua_toboolean(L, 3)) *ptr |= bit; /* set */ else *ptr &= ~bit; /* clear */ } break; case LUA_TSTRING: { size_t len; const char *s = lua_tolstring(L, 3, &len); memcpy(ptr, s, len); } break; default: luaL_argerror(L, 3, "membuf value expected"); } return 0; }
ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r) { ngx_int_t rc; u_char *err_msg; size_t len; #if (NGX_PCRE) ngx_pool_t *old_pool; #endif /* set Lua VM panic handler */ lua_atpanic(L, ngx_http_lua_atpanic); NGX_LUA_EXCEPTION_TRY { /* initialize nginx context in Lua VM, code chunk at stack top sp = 1 */ ngx_http_lua_log_by_lua_env(L, r); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); #endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ /* protected call user code */ rc = lua_pcall(L, 0, 1, 1); lua_remove(L, 1); /* remove traceback function */ #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ ngx_http_lua_pcre_malloc_done(old_pool); #endif if (rc != 0) { /* error occured when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { err_msg = (u_char *) "unknown reason"; len = sizeof("unknown reason") - 1; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to run log_by_lua*: %*s", len, err_msg); lua_settop(L, 0); /* clear remaining elems on stack */ return NGX_ERROR; } } NGX_LUA_EXCEPTION_CATCH { dd("nginx execution restored"); return NGX_ERROR; } /* clear Lua stack */ lua_settop(L, 0); return NGX_OK; }
int ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, u_char *last, int max) { u_char *p, *q; u_char *src, *dst; unsigned parsing_value; size_t len; int count = 0; int top; top = lua_gettop(L); p = buf; parsing_value = 0; q = p; while (p != last) { if (*p == '=' && ! parsing_value) { /* key data is between p and q */ src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, NGX_UNESCAPE_URI_COMPONENT); dd("pushing key %.*s", (int) (dst - q), q); /* push the key */ lua_pushlstring(L, (char *) q, dst - q); /* skip the current '=' char */ p++; q = p; parsing_value = 1; } else if (*p == '&') { /* reached the end of a key or a value, just save it */ src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, NGX_UNESCAPE_URI_COMPONENT); dd("pushing key or value %.*s", (int) (dst - q), q); /* push the value or key */ lua_pushlstring(L, (char *) q, dst - q); /* skip the current '&' char */ p++; q = p; if (parsing_value) { /* end of the current pair's value */ parsing_value = 0; } else { /* the current parsing pair takes no value, * just push the value "true" */ dd("pushing boolean true"); lua_pushboolean(L, 1); } (void) lua_tolstring(L, -2, &len); if (len == 0) { /* ignore empty string key pairs */ dd("popping key and value..."); lua_pop(L, 2); } else { dd("setting table..."); ngx_http_lua_set_multi_value_table(L, top); } if (max > 0 && ++count == max) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua hit query args limit %d", max); return 1; } } else { p++; } } if (p != q || parsing_value) { src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, NGX_UNESCAPE_URI_COMPONENT); dd("pushing key or value %.*s", (int) (dst - q), q); lua_pushlstring(L, (char *) q, dst - q); if (!parsing_value) { dd("pushing boolean true..."); lua_pushboolean(L, 1); } (void) lua_tolstring(L, -2, &len); if (len == 0) { /* ignore empty string key pairs */ dd("popping key and value..."); lua_pop(L, 2); } else { dd("setting table..."); ngx_http_lua_set_multi_value_table(L, top); } } dd("gettop: %d", lua_gettop(L)); dd("type: %s", lua_typename(L, lua_type(L, 1))); if (lua_gettop(L) != top) { return luaL_error(L, "internal error: stack in bad state"); } return 1; }
void script_request(lua_State *L, char **buf, size_t *len) { lua_getglobal(L, "request"); lua_call(L, 0, 1); *buf = (char *) lua_tolstring(L, 1, len); lua_pop(L, 1); }
bool LuaState::ExecuteLoadString(string const &s, LoadStringResult &result) { if (!this->have_load_string) return false; int stack_size = lua_gettop(this->L); lua_getglobal(this->L, LOAD_STRING_FUNCTION); lua_pushlstring(this->L, s.c_str(), s.length()); if (lua_pcall(this->L, 1, LUA_MULTRET, 0) != 0) { result.execution_success = false; size_t len = 0; const char *error = lua_tolstring(this->L, -1, &len); result.lua_error = string(error, len); lua_pop(this->L, 1); return true; } result.execution_success = true; int nresults = lua_gettop(L) - stack_size; if (nresults < 1) { result.return_type = result.INVALID; return true; } // as a refresher, the following type conventions are handled: // // nil // bool // 1 or more strings // 1 or more messages // 1 or more envelopes // table, <any of above except nil> int stpos = -1 * nresults; int value_results = nresults; bool got_type = false; // handle the one off case for a single nil if (nresults == 1 && lua_isnil(this->L, -1)) { result.return_type = result.NIL; goto LOAD_STRING_POP_AND_RETURN; } // so we have a type that could be repeated // the first and only first one could be a table, so handle that if (lua_istable(this->L, stpos)) { value_results--; if (value_results < 1) { result.return_type = result.INVALID; goto LOAD_STRING_POP_AND_RETURN; } // @todo should we error if type is not a string? lua_getfield(this->L, stpos, "bucket"); if (lua_isstring(this->L, -1)) { size_t len; const char *s = lua_tolstring(this->L, -1, &len); result.has_bucket = true; result.bucket = string(s, len); } lua_pop(this->L, 1); lua_getfield(this->L, stpos, "set"); if (lua_isstring(this->L, -1)) { size_t len; const char *s = lua_tolstring(this->L, -1, &len); result.has_set = true; result.set = string(s, len); } lua_pop(this->L, 1); stpos++; } // ok, now iterate through the remaining values // make sure the types are consistent along the way for (int i = stpos; i < 0; i++) { if (lua_isboolean(this->L, i)) { // multiple booleans doesn't make any sense. catch it if (value_results > 1) { result.return_type = result.INVALID; goto LOAD_STRING_POP_AND_RETURN; } result.return_type = lua_toboolean(this->L, i) ? result.BOOLTRUE : result.BOOLFALSE; got_type = true; continue; } if (lua_isstring(this->L, i)) { // can't mix types if (got_type && result.return_type != result.STRING) { result.return_type = result.INVALID; goto LOAD_STRING_POP_AND_RETURN; } size_t len = 0; const char *s = lua_tolstring(this->L, i, &len); result.return_type = result.STRING; result.strings.push_back(string(s, len)); got_type = true; continue; } void *ud = lua_touserdata(this->L, i); if (ud == NULL) { result.return_type = result.INVALID; break; } if (lua_getmetatable(this->L, i) == 0) { result.return_type = result.INVALID; break; } // is it an envelope type lua_getfield(this->L, LUA_REGISTRYINDEX, LUA_ENVELOPE_METHOD_TABLENAME); if (lua_rawequal(this->L, -2, -1)) { // don't need the metatables lua_pop(this->L, 2); if (got_type && result.return_type != result.ENVELOPE) { result.return_type = result.INVALID; goto LOAD_STRING_POP_AND_RETURN; } envelope_udata *ed = (envelope_udata *)ud; // we copy the envelope since poorly designed Lua scripts could // do evil things with the envelope in Lua land and we don't want // that to impact us here result.envelopes.push_back(Envelope(*ed->e)); result.return_type = result.ENVELOPE; got_type = true; continue; } // remove metatables lua_pop(this->L, 2); // @todo handle message case result.return_type = result.INVALID; break; } LOAD_STRING_POP_AND_RETURN: lua_pop(this->L, nresults); return true; }
static int ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { ngx_http_request_t *r; ngx_str_t args; const char *msg; size_t len; u_char *p; if (lua_gettop(L) != 1) { return luaL_error(L, "expecting 1 argument but seen %d", lua_gettop(L)); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); switch (lua_type(L, 1)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 1, &len); args.data = ngx_palloc(r->pool, len); if (args.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(args.data, p, len); args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 1, &args); dd("args: %.*s", (int) args.len, args.data); break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 1, msg); } dd("args: %.*s", (int) args.len, args.data); r->args.data = args.data; r->args.len = args.len; r->valid_unparsed_uri = 0; return 0; }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; size_t nargs; int rc; int n; int always_forward_body = 0; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; size_t sr_flags_len; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_post_subrequest_data_t *psr_data; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua location capture, uri:\"%V\" c:%ud", &r->uri, r->main->count); sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); sr_flags_len = nsubreqs * sizeof(uint8_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len + sr_flags_len); if (p == NULL) { return luaL_error(L, "no memory"); } coctx->sr_statuses = (void *) p; p += sr_statuses_len; coctx->sr_headers = (void *) p; p += sr_headers_len; coctx->sr_bodies = (void *) p; p += sr_bodies_len; coctx->sr_flags = (void *) p; coctx->nsubreqs = nsubreqs; coctx->pending_subreqs = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { coctx->pending_subreqs++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; ngx_str_null(&extra_args); if (extra_vars != NULL) { /* flush out existing elements in the array */ extra_vars->nelts = 0; } vars_action = 0; custom_ctx = 0; if (nargs == 2) { /* check out the options table */ lua_rawgeti(L, 2, 2); /* queries query uri opts */ dd("queries query uri opts: %d", lua_gettop(L)); if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " "subrequest %d, but got %s", index, luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); /* check the args option */ lua_getfield(L, 4, "args"); type = lua_type(L, -1); switch (type) { case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, -1, &extra_args); break; case LUA_TNIL: /* do nothing */ break; case LUA_TNUMBER: case LUA_TSTRING: extra_args.data = (u_char *) lua_tolstring(L, -1, &len); extra_args.len = len; break; default: return luaL_error(L, "Bad args option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the vars option */ lua_getfield(L, 4, "vars"); switch (lua_type(L, -1)) { case LUA_TTABLE: ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; case LUA_TNIL: /* do nothing */ break; default: return luaL_error(L, "Bad vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS; } break; default: return luaL_error(L, "Bad share_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the copy_all_vars option */ lua_getfield(L, 4, "copy_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS; } break; default: return luaL_error(L, "Bad copy_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "forward_body" option */ lua_getfield(L, 4, "always_forward_body"); always_forward_body = lua_toboolean(L, -1); lua_pop(L, 1); dd("always foward body: %d", always_forward_body); /* check the "method" option */ lua_getfield(L, 4, "method"); type = lua_type(L, -1); if (type == LUA_TNIL) { method = NGX_HTTP_GET; } else { if (type != LUA_TNUMBER) { return luaL_error(L, "Bad http request method"); } method = (ngx_uint_t) lua_tonumber(L, -1); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "ctx" option */ lua_getfield(L, 4, "ctx"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " "expected a Lua table", lua_typename(L, type)); } custom_ctx = 1; } else { lua_pop(L, 1); } dd("queries query uri opts ctx?: %d", lua_gettop(L)); /* check the "body" option */ lua_getfield(L, 4, "body"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TSTRING && type != LUA_TNUMBER) { return luaL_error(L, "Bad http request body"); } body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "no memory"); } q = (u_char *) lua_tolstring(L, -1, &len); dd("request body: [%.*s]", (int) len, q); if (len) { b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return luaL_error(L, "no memory"); } b->last = ngx_copy(b->last, q, len); body->bufs = ngx_alloc_chain_link(r->pool); if (body->bufs == NULL) { return luaL_error(L, "no memory"); } body->bufs->buf = b; body->bufs->next = NULL; body->buf = b; } } lua_pop(L, 1); /* pop the body */ /* stack: queries query uri opts ctx? */ lua_remove(L, 4); /* stack: queries query uri ctx? */ dd("queries query uri ctx?: %d", lua_gettop(L)); } else { method = NGX_HTTP_GET; } /* stack: queries query uri ctx? */ p = (u_char *) luaL_checklstring(L, 3, &len); uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "memory allocation error"); } ngx_memcpy(uri.data, p, len); uri.len = len; ngx_str_null(&args); flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { if (extra_args.len) { p = ngx_palloc(r->pool, extra_args.len); if (p == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(p, extra_args.data, extra_args.len); args.data = p; args.len = extra_args.len; } } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "no memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, extra_args.data, extra_args.len); args.data = p; args.len = len; } p = ngx_pnalloc(r->pool, sizeof(ngx_http_post_subrequest_t) + sizeof(ngx_http_lua_ctx_t) + sizeof(ngx_http_lua_post_subrequest_data_t)); if (p == NULL) { return luaL_error(L, "no memory"); } psr = (ngx_http_post_subrequest_t *) p; p += sizeof(ngx_http_post_subrequest_t); sr_ctx = (ngx_http_lua_ctx_t *) p; p += sizeof(ngx_http_lua_ctx_t); psr_data = (ngx_http_lua_post_subrequest_data_t *) p; ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL * sr_ctx->body = NULL */ psr_data->ctx = sr_ctx; psr_data->pr_co_ctx = coctx; psr->handler = ngx_http_lua_post_subrequest; psr->data = psr_data; rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } ngx_http_lua_init_ctx(sr, sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; sr_ctx->last_body = &sr_ctx->body; sr_ctx->vm_state = ctx->vm_state; ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body, body, vars_action, extra_vars); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } ctx->no_abort = 1; return lua_yield(L, 0); }
int KSystemScriptTable::LuaSaveDataToFile(Lua_State* L) { int nRetCode = false; IFile *piFile = NULL; const char *pcszFile = NULL; const char *pcsBuff = NULL; unsigned uFilePathLength = 0; size_t uBuffSize = 0; int i = 0; char szFile[MAX_PATH]; char szPath[MAX_PATH]; KGLOG_PROCESS_ERROR(L); nRetCode = lua_gettop(L); KGLOG_PROCESS_ERROR(nRetCode == 2); pcsBuff = lua_tolstring(L, 1, &uBuffSize); KGLOG_PROCESS_ERROR(pcsBuff); KGLOG_PROCESS_ERROR(uBuffSize > 0); pcszFile = lua_tostring(L, 2); KGLOG_PROCESS_ERROR(pcszFile); KGLOG_PROCESS_ERROR(pcszFile[0]); uFilePathLength = snprintf( szFile, sizeof(szFile), "%s\\%s", F_UI_USER_DATA_FOLDER, pcszFile ); KGLOG_PROCESS_ERROR(uFilePathLength > 0); szFile[sizeof(szFile) - 1] = '\0'; FormatFilePath(szFile); szPath[0] = '\0'; for (i = uFilePathLength; i >= 0; i--) { if (szFile[i] != '/' && szFile[i] != '\\') continue; ASSERT(i < sizeof(szPath)); strncpy(szPath, szFile, i); szPath[i] = '\0'; break; } nRetCode = KUiConfig::IsFilePathExist(szPath); if (!nRetCode) { nRetCode = KUiConfig::CreatePath(szPath); KGLOG_PROCESS_ERROR(nRetCode); } piFile = g_CreateFile(szFile); KGLOG_PROCESS_ERROR(piFile); nRetCode = piFile->Write(pcsBuff, (unsigned long)uBuffSize); KGLOG_PROCESS_ERROR(nRetCode == uBuffSize); Exit0: SAFE_RELEASE(piFile); return 0; }
static int ts_lua_transform_handler(TSCont contp, ts_lua_transform_ctx *transform_ctx) { TSVConn output_conn; TSVIO input_vio; TSIOBufferReader input_reader; TSIOBufferBlock blk; int64_t towrite, blk_len, upstream_done, avail, left; const char *start; const char *res; size_t res_len; int ret, eos; lua_State *L; TSMutex mtxp; L = transform_ctx->hctx->lua; mtxp = transform_ctx->hctx->mctx->mutexp; output_conn = TSTransformOutputVConnGet(contp); input_vio = TSVConnWriteVIOGet(contp); input_reader = TSVIOReaderGet(input_vio); if (!transform_ctx->output_buffer) { transform_ctx->output_buffer = TSIOBufferCreate(); transform_ctx->output_reader = TSIOBufferReaderAlloc(transform_ctx->output_buffer); transform_ctx->output_vio = TSVConnWrite(output_conn, contp, transform_ctx->output_reader, INT64_MAX); } if (!TSVIOBufferGet(input_vio)) { TSVIONBytesSet(transform_ctx->output_vio, transform_ctx->total); TSVIOReenable(transform_ctx->output_vio); return 1; } if (transform_ctx->eos) { return 1; } left = towrite = TSVIONTodoGet(input_vio); upstream_done = TSVIONDoneGet(input_vio); avail = TSIOBufferReaderAvail(input_reader); eos = 0; if (left <= avail) eos = 1; if (towrite > avail) towrite = avail; TSMutexLock(mtxp); blk = TSIOBufferReaderStart(input_reader); do { start = TSIOBufferBlockReadStart(blk, input_reader, &blk_len); lua_pushlightuserdata(L, transform_ctx); lua_rawget(L, LUA_GLOBALSINDEX); /* push function */ if (towrite > blk_len) { lua_pushlstring(L, start, (size_t)blk_len); towrite -= blk_len; } else { lua_pushlstring(L, start, (size_t)towrite); towrite = 0; } if (!towrite && eos) { lua_pushinteger(L, 1); /* second param, not finish */ } else { lua_pushinteger(L, 0); /* second param, not finish */ } if (lua_pcall(L, 2, 2, 0)) { fprintf(stderr, "lua_pcall failed: %s\n", lua_tostring(L, -1)); } ret = lua_tointeger(L, -1); /* 0 is not finished, 1 is finished */ res = lua_tolstring(L, -2, &res_len); if (res && res_len) { TSIOBufferWrite(transform_ctx->output_buffer, res, res_len); transform_ctx->total += res_len; } lua_pop(L, 2); if (ret || (eos && !towrite)) { // EOS eos = 1; break; } blk = TSIOBufferBlockNext(blk); } while (blk && towrite > 0); TSMutexUnlock(mtxp); TSIOBufferReaderConsume(input_reader, avail); TSVIONDoneSet(input_vio, upstream_done + avail); if (eos) { transform_ctx->eos = 1; TSVIONBytesSet(transform_ctx->output_vio, transform_ctx->total); TSVIOReenable(transform_ctx->output_vio); TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio); } else { TSVIOReenable(transform_ctx->output_vio); TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio); } return 1; }
void amf0_encode(lua_State *L, amf_buf *buf, int avmplus, int idx, int ridx) { int array_len, old_top, ref; size_t len; const char *str; abs_idx(L, idx); abs_idx(L, ridx); old_top = lua_gettop(L); switch (lua_type(L, idx)) { case LUA_TNIL: amf_buf_append_char(buf, AMF0_NULL); break; case LUA_TBOOLEAN: amf_buf_append_char(buf, AMF0_BOOLEAN); amf_buf_append_char(buf, lua_toboolean(L, idx) ? 1 : 0); break; case LUA_TNUMBER: amf_buf_append_char(buf, AMF0_NUMBER); amf0_encode_number(buf, lua_tonumber(L, idx)); break; case LUA_TSTRING: str = lua_tolstring(L, idx, &len); amf0_encode_string(buf, str, len); break; case LUA_TTABLE: { if (avmplus) { lua_newtable(L); lua_newtable(L); lua_newtable(L); int top = lua_gettop(L); amf3_encode(L, buf, idx, top-2, top-1, top); lua_pop(L, 3); } else { ref = amf0_encode_ref(buf, L, idx, ridx); if (ref >= 0) { break; } array_len = strict_array_length(L, idx); if (array_len == 0) { amf_buf_append_char(buf, AMF0_NULL); } else if (array_len > 0) { amf0_encode_table_as_array(buf, L, idx, ridx, array_len); } else { amf0_encode_table_as_object(buf, L, idx, ridx); } } break; } } assert(lua_gettop(L) == old_top); }
static int _lua_echo(epdata_t *epd, lua_State *L, int nargs, int can_yield) { size_t len = 0; int have = 0; epd->next_out = NULL; if(lua_istable(L, 1)) { len = lua_calc_strlen_in_table(L, 1, 2, 0 /* strict */); if(len < 1) { return 0; } char *buf = temp_buf; if(len > 8192) { buf = malloc(len); if(!buf) { return 0; } lua_copy_str_in_table(L, 1, buf); have = network_send(epd, buf, len); if(have > 0 && can_yield) { epd->next_out = malloc(have); memcpy(epd->next_out, buf + (len - have), have); } free(buf); } else { lua_copy_str_in_table(L, 1, buf); have = network_send(epd, buf, len); if(have > 0 && can_yield) { epd->next_out = malloc(have); memcpy(epd->next_out, buf + (len - have), have); } } } else { const char *data = NULL; int i = 0; for(i = 1; i <= nargs; i++) { if(lua_isboolean(L, i)) { char *buf = NULL; if(lua_toboolean(L, i)) { buf = "true"; have = network_send(epd, buf, 4); } else { buf = "false"; have = network_send(epd, buf, 5); } if(have > 0 && can_yield) { epd->next_out = malloc(have); memcpy(epd->next_out, buf + (len - have), have); } } else { data = lua_tolstring(L, i, &len); have = network_send(epd, data, len); if(have > 0 && can_yield) { epd->next_out = malloc(have); memcpy(epd->next_out, data + (len - have), have); } } } } if(epd->next_out) { if(network_flush(epd) == 1) { epd->next_proc = send_then_send; epd->next_out_len = have; return have; } else { LOGF(ERR, "flush error"); free(epd->next_out); epd->next_out = NULL; return 0; } } return 0; }
void amf3_encode(lua_State *L, amf_buf *buf, int idx, int sidx, int oidx, int tidx) { int old_top, array_len; const char *str; size_t str_len; old_top = lua_gettop(L); switch (lua_type(L, idx)) { case LUA_TNIL: { amf_buf_append_char(buf, AMF3_NULL); break; } case LUA_TBOOLEAN: { if (lua_toboolean(L, idx)) { amf_buf_append_char(buf, AMF3_TRUE); } else { amf_buf_append_char(buf, AMF3_FALSE); } break; } case LUA_TNUMBER: { lua_Number n = lua_tonumber(L, idx); /* encode as double */ if (floor(n) != n || n < AMF3_MIN_INT || n > AMF3_MAX_INT) { amf_buf_append_char(buf, AMF3_DOUBLE); amf_buf_append_double(buf, n); } else { amf_buf_append_char(buf, AMF3_INTEGER); amf_buf_append_u29(buf, (int)n); } break; } case LUA_TSTRING: { str = lua_tolstring(L, idx, &str_len); amf_buf_append_char(buf, AMF3_STRING); amf3_encode_string(L, buf, idx, sidx); break; } case LUA_TTABLE: array_len = strict_array_length(L, idx); if (array_len == 0) { amf_buf_append_char(buf, AMF3_NULL); } else if (array_len > 0) { amf3_encode_table_as_array(L, buf, idx, sidx, oidx, tidx, array_len); } else { amf3_encode_table_as_object(L, buf, idx, sidx, oidx, tidx); } } assert(lua_gettop(L) == old_top); }
int lua_print_error(lua_State *L) { epdata_t *epd = get_epd(L); if(!epd) { lua_pushnil(L); lua_pushstring(L, "miss epd!"); return 2; } lua_Debug ar; lua_getstack(L, 1, &ar); lua_getinfo(L, "nSl", &ar); if(!ar.source) { return 0; } snprintf(temp_buf_1024, 1024, "%s:%d", ar.source + 1, ar.currentline); lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if(!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if(!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ size_t len = 0; char *msg = (char *)lua_tolstring(L, -1, &len); int i = 0; memcpy(temp_buf2, "<h3>Error: ", 11); int j = 11; int is_first_line = 1; for(i = 0; i < len; i++) { temp_buf[i] = (msg[i] != '\n' ? msg[i] : ' '); if(is_first_line && msg[i] == '\n') { memcpy(temp_buf2 + j, "</h3>\n<pre>", 11); j += 11; } temp_buf2[j++] = msg[i]; } temp_buf[len] = '\0'; memcpy(temp_buf2 + j, "\n</pre>", 7); j += 7; temp_buf2[j] = '\0'; _LOGF(ERR, temp_buf_1024, "%s", temp_buf); network_send(epd, temp_buf2, j); return 1; }
/** * @upvalue z_stream - Memory for the z_stream. * @upvalue remainder - Any remainder from the last deflate call. * * @param string - "print" to deflate stream. * @param int - flush output buffer? Z_SYNC_FLUSH, Z_FULL_FLUSH, or Z_FINISH. * * if no params, terminates the stream (as if we got empty string and Z_FINISH). */ static int lz_filter_impl(lua_State *L, int (*filter)(z_streamp, int), int (*end)(z_streamp), const char* name) { int flush = Z_NO_FLUSH, result; z_stream* stream; luaL_Buffer buff; size_t avail_in; if ( filter == deflate ) { const char *const opts[] = { "none", "sync", "full", "finish", NULL }; flush = luaL_checkoption(L, 2, opts[0], opts); if ( flush ) flush++; /* Z_NO_FLUSH(0) Z_SYNC_FLUSH(2), Z_FULL_FLUSH(3), Z_FINISH (4) */ /* No arguments or nil, we are terminating the stream: */ if ( lua_gettop(L) == 0 || lua_isnil(L, 1) ) { flush = Z_FINISH; } } stream = (z_stream*)lua_touserdata(L, lua_upvalueindex(1)); if ( stream == NULL ) { if ( lua_gettop(L) >= 1 && lua_isstring(L, 1) ) { lua_pushfstring(L, "IllegalState: calling %s function when stream was previously closed", name); lua_error(L); } lua_pushstring(L, ""); lua_pushboolean(L, 1); return 2; /* Ignore duplicate calls to "close". */ } luaL_buffinit(L, &buff); if ( lua_gettop(L) > 1 ) lua_pushvalue(L, 1); if ( lua_isstring(L, lua_upvalueindex(2)) ) { lua_pushvalue(L, lua_upvalueindex(2)); if ( lua_gettop(L) > 1 && lua_isstring(L, -2) ) { lua_concat(L, 2); } } /* Do the actual deflate'ing: */ if (lua_gettop(L) > 0) { stream->next_in = (unsigned char*)lua_tolstring(L, -1, &avail_in); } else { stream->next_in = NULL; avail_in = 0; } stream->avail_in = (uInt)avail_in; if ( ! stream->avail_in && ! flush ) { /* Passed empty string, make it a noop instead of erroring out. */ lua_pushstring(L, ""); lua_pushboolean(L, 0); lua_pushinteger(L, stream->total_in); lua_pushinteger(L, stream->total_out); return 4; } do { stream->next_out = (unsigned char*)luaL_prepbuffer(&buff); stream->avail_out = LUAL_BUFFERSIZE; result = filter(stream, flush); if ( Z_BUF_ERROR != result ) { /* Ignore Z_BUF_ERROR since that just indicates that we * need a larger buffer in order to proceed. Thanks to * Tobias Markmann for finding this bug! */ lz_assert(L, result, stream, __FILE__, __LINE__); } luaL_addsize(&buff, LUAL_BUFFERSIZE - stream->avail_out); } while ( stream->avail_out == 0 ); /* Need to do this before we alter the stack: */ luaL_pushresult(&buff); /* Save remainder in lua_upvalueindex(2): */ if ( NULL != stream->next_in ) { lua_pushlstring(L, (char*)stream->next_in, stream->avail_in); lua_replace(L, lua_upvalueindex(2)); } /* "close" the stream/remove finalizer: */ if ( result == Z_STREAM_END ) { /* Clear-out the metatable so end is not called twice: */ lua_pushnil(L); lua_setmetatable(L, lua_upvalueindex(1)); /* nil the upvalue: */ lua_pushnil(L); lua_replace(L, lua_upvalueindex(1)); /* Close the stream: */ lz_assert(L, end(stream), stream, __FILE__, __LINE__); lua_pushboolean(L, 1); } else { lua_pushboolean(L, 0); } lua_pushinteger(L, stream->total_in); lua_pushinteger(L, stream->total_out); return 4; }
int lua_header(lua_State *L) { epdata_t *epd = get_epd(L); if(!epd) { lua_pushnil(L); lua_pushstring(L, "miss epd!"); return 2; } if(epd->websocket) { return 0; } if(lua_gettop(L) < 1) { return 0; } if(epd->header_sended != 0) { lua_pushnil(L); lua_pushstring(L, "respone header has been sended"); return 2; } int t = lua_type(L, 1); size_t dlen = 0; const char *data = NULL; int ret = 0; if(t == LUA_TSTRING) { data = lua_tolstring(L, 1, &dlen); if(stristr(data, "content-length", dlen) != data) { ret = network_send_header(epd, data); } } else if(t == LUA_TTABLE) { int len = lua_objlen(L, 1), i = 0; for(i = 0; i < len; i++) { lua_pushinteger(L, i + 1); lua_gettable(L, -2); if(lua_isstring(L, -1)) { data = lua_tolstring(L, -1, &dlen); if(stristr(data, "content-length", dlen) != data) { ret = network_send_header(epd, lua_tostring(L, -1)); } } lua_pop(L, 1); } } if(ret == -1) { lua_pushnil(L); lua_pushstring(L, "respone header too big"); return 2; } else if(ret == 0) { lua_pushnil(L); } else { lua_pushboolean(L, 1); } return 1; }
static int decrypt(lua_State* pState) { AESObject* aes = (AESObject*)lua_touserdata(pState, 1); unsigned char *buffer, *str; unsigned char temp[BLOCK_SIZE]; int i, j, len; str = lua_tolstring(pState, 2, &len); if (len == 0) { lua_pushstring(pState, ""); return 1; } if ( (len % BLOCK_SIZE) !=0 && (aes->mode!=MODE_CFB)) { luaL_error(pState, "Input strings must be " "a multiple of %d in length", BLOCK_SIZE); return 0; } if (aes->mode == MODE_CFB && (len % (aes->segment_size/8) !=0)) { luaL_error(pState, "aInput strings must be a multiple of " "the segment size %d in length", aes->segment_size/8); return 0; } buffer = (char*)malloc(len); if (!buffer) { luaL_error(pState, "alloc memory error"); return 0; } switch(aes->mode) { case(MODE_ECB): for(i=0; i<len; i+=BLOCK_SIZE) { block_decrypt(&(aes->st), str+i, buffer+i); } break; case(MODE_CBC): for(i=0; i<len; i+=BLOCK_SIZE) { memcpy(aes->oldCipher, aes->IV, BLOCK_SIZE); block_decrypt(&(aes->st), str+i, temp); for(j=0; j<BLOCK_SIZE; j++) { buffer[i+j]=temp[j]^aes->IV[j]; aes->IV[j]=str[i+j]; } } break; case(MODE_CFB): for(i=0; i<len; i+=aes->segment_size/8) { block_encrypt(&(aes->st), aes->IV, temp); for (j=0; j<aes->segment_size/8; j++) { buffer[i+j] = str[i+j]^temp[j]; } if (aes->segment_size == BLOCK_SIZE * 8) { /* s == b: segment size is identical to the algorithm block size */ memcpy(aes->IV, str + i, BLOCK_SIZE); } else if ((aes->segment_size % 8) == 0) { int sz = aes->segment_size/8; memmove(aes->IV, aes->IV + sz, BLOCK_SIZE-sz); memcpy(aes->IV + BLOCK_SIZE - sz, str + i, sz); } else { /* segment_size is not a multiple of 8; currently this can't happen */ } } break; case (MODE_OFB): for(i=0; i<len; i+=BLOCK_SIZE) { block_encrypt(&(aes->st), aes->IV, temp); memcpy(aes->IV, temp, BLOCK_SIZE); for(j=0; j<BLOCK_SIZE; j++) { buffer[i+j] = str[i+j] ^ aes->IV[j]; } } break; default: free(buffer); luaL_error(pState, "not support mode"); return 0; } lua_pushlstring(pState, buffer, len); free(buffer); return 1; }
LUA_API const char* luaS_tolstring32(lua_State *L, int index, int* len) { size_t l; const char* ret = lua_tolstring(L, index, &l); *len = (int)l; return ret; }
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { const char *s = lua_tolstring(L, narg, len); if (!s) tag_error(L, narg, LUA_TSTRING); return s; }
/** * @brief Handles the CLI input. * * @param wid Window receiving the input. * @param unused Unused. */ static void cli_input( unsigned int wid, char *unused ) { (void) unused; int status; char *str; lua_State *L; char buf[LINE_LENGTH]; /* Get the input. */ str = window_getInput( wid, "inpInput" ); /* Ignore useless stuff. */ if (str == NULL) return; /* Put the message in the console. */ snprintf( buf, LINE_LENGTH, "%s %s", cli_firstline ? "> " : ">>", str ); cli_addMessage( buf ); /* Set up state. */ L = cli_state; /* Set up for concat. */ if (!cli_firstline) /* o */ lua_pushliteral(L, "\n"); /* o \n */ /* Load the string. */ lua_pushstring( L, str ); /* s */ /* Concat. */ if (!cli_firstline) /* o \n s */ lua_concat(L, 3); /* s */ status = luaL_loadbuffer( L, lua_tostring(L,-1), lua_strlen(L,-1), "=cli" ); /* String isn't proper Lua yet. */ if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); if (strstr(msg, LUA_QL("<eof>")) == tp) { /* Pop the loaded buffer. */ lua_pop(L, 1); cli_firstline = 0; } else { /* Real error, spew message and break. */ cli_addMessage( lua_tostring(L, -1) ); lua_settop(L, 0); cli_firstline = 1; } } /* Print results - all went well. */ else if (status == 0) { lua_remove(L,1); if (lua_pcall(L, 0, LUA_MULTRET, 0)) { cli_addMessage( lua_tostring(L, -1) ); lua_pop(L,1); } if (lua_gettop(L) > 0) { lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) cli_addMessage( "Error printing results." ); } /* Clear stack. */ lua_settop(L, 0); cli_firstline = 1; } /* Clear the box now. */ window_setInput( wid, "inpInput", NULL ); }
static int ngx_http_lua_ngx_exec(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t uri; ngx_str_t args, user_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; const char *msg; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_str_null(&args); /* read the 1st argument (uri) */ p = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { return luaL_error(L, "The uri argument is empty"); } uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(uri.data, p, len); uri.len = len; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); ngx_http_lua_check_if_abortable(L, ctx); if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n == 2) { /* read the 2nd argument (args) */ dd("args type: %s", luaL_typename(L, 2)); switch (lua_type(L, 2)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 2, &len); user_args.data = ngx_palloc(r->pool, len); if (user_args.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(user_args.data, p, len); user_args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 2, &user_args); dd("user_args: %.*s", (int) user_args.len, user_args.data); break; case LUA_TNIL: ngx_str_null(&user_args); break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 2, msg); } } else { user_args.data = NULL; user_args.len = 0; } if (user_args.len) { if (args.len == 0) { args = user_args; } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { return luaL_error(L, "no memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, user_args.data, user_args.len); args.data = p; args.len += user_args.len + 1; } } if (r->header_sent || ctx->header_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } ctx->exec_uri = uri; ctx->exec_args = args; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exec \"%V?%V\"", &ctx->exec_uri, &ctx->exec_args); return lua_yield(L, 0); }
static int ngx_http_lua_shdict_set_helper(lua_State *L, int flags) { int i, n; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; double num; u_char c; lua_Number exptime = 0; u_char *p; ngx_rbtree_node_t *node; ngx_time_t *tp; ngx_shm_zone_t *zone; int forcible = 0; /* indicates whether to foricibly override other * valid entries */ int32_t user_flags = 0; n = lua_gettop(L); if (n != 3 && n != 4 && n != 5) { return luaL_error(L, "expecting 3, 4 or 5 arguments, " "but only seen %d", n); } zone = lua_touserdata(L, 1); if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } ctx = zone->data; if (lua_isnil(L, 2)) { lua_pushnil(L); lua_pushliteral(L, "nil key"); return 2; } key.data = (u_char *) luaL_checklstring(L, 2, &key.len); if (key.len == 0) { lua_pushnil(L); lua_pushliteral(L, "empty key"); return 2; } if (key.len > 65535) { lua_pushnil(L); lua_pushliteral(L, "key too long"); return 2; } hash = ngx_crc32_short(key.data, key.len); value_type = lua_type(L, 3); switch (value_type) { case LUA_TSTRING: value.data = (u_char *) lua_tolstring(L, 3, &value.len); break; case LUA_TNUMBER: value.len = sizeof(double); num = lua_tonumber(L, 3); value.data = (u_char *) # break; case LUA_TBOOLEAN: value.len = sizeof(u_char); c = lua_toboolean(L, 3) ? 1 : 0; value.data = &c; break; case LUA_TNIL: if (flags & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { lua_pushnil(L); lua_pushliteral(L, "attempt to add or replace nil values"); return 2; } ngx_str_null(&value); break; default: lua_pushnil(L); lua_pushliteral(L, "bad value type"); return 2; } if (n >= 4) { exptime = luaL_checknumber(L, 4); if (exptime < 0) { exptime = 0; } } if (n == 5) { user_flags = (uint32_t) luaL_checkinteger(L, 5); } ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returned %d", (int) rc); if (flags & NGX_HTTP_LUA_SHDICT_REPLACE) { if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "not found"); lua_pushboolean(L, forcible); return 3; } /* rc == NGX_OK */ goto replace; } if (flags & NGX_HTTP_LUA_SHDICT_ADD) { if (rc == NGX_OK) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "exists"); lua_pushboolean(L, forcible); return 3; } if (rc == NGX_DONE) { /* exists but expired */ dd("go to replace"); goto replace; } /* rc == NGX_DECLINED */ dd("go to insert"); goto insert; } if (rc == NGX_OK || rc == NGX_DONE) { if (value_type == LUA_TNIL) { goto remove; } replace: if (value.data && value.len == (size_t) sd->value_len) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value " "size matched, reusing it"); ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); sd->key_len = (u_short) key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) (exptime * 1000); } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) value.len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, forcible); return 3; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry but value size " "NOT matched, removing it first"); remove: ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); } insert: /* rc == NGX_DECLINED or value size unmatch */ if (value.data == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, 0); return 3; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) + key.len + value.len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { if (flags & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "no memory"); return 2; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: overriding non-expired items " "due to memory shortage for entry \"%V\"", &key); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { break; } forcible = 1; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node != NULL) { goto allocated; } } ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "no memory"); lua_pushboolean(L, forcible); return 3; } allocated: sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; sd->key_len = (u_short) key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) (exptime * 1000); } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) value.len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, forcible); return 3; }
static int _sasl_s_canon_user(sasl_conn_t *conn, void *context, const char *user, unsigned ulen, unsigned flags, const char *user_realm, char *out_user, unsigned out_umax, unsigned *out_ulen) { struct _sasl_ctx *ctxp = context; if (!conn || !context || !user || ctxp->magic != CYRUSSASL_MAGIC) return SASL_BADPARAM; if (!(flags & SASL_CU_AUTHID) && !(flags & SASL_CU_AUTHZID)) return SASL_BADPARAM; if (!out_user || !out_ulen || out_umax == 0) return SASL_BADPARAM; if (ctxp->canon_cb_ref == LUA_REFNIL) { if (ulen >= out_umax) return SASL_BUFOVER; /* out_user may be the same as user, so memmove, not memcpy */ memmove(out_user, user, ulen); out_user[ulen] = '\0'; *out_ulen = ulen; set_context_user(context, user, ulen); return SASL_OK; } /* We have a callback to deal with. */ int ret = SASL_OK; const char *str = NULL; size_t len = 0; /* Function to call */ lua_rawgeti(ctxp->L, LUA_REGISTRYINDEX, ctxp->canon_cb_ref); /* Username */ lua_pushlstring(ctxp->L, user, ulen); /* Realm */ lua_pushstring(ctxp->L, user_realm); /* flags (the type of username) */ if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) lua_pushliteral(ctxp->L, "both"); else if (flags & SASL_CU_AUTHID) lua_pushliteral(ctxp->L, "authcid"); else lua_pushliteral(ctxp->L, "authzid"); /* Perform: str = cb(user, user_realm, "both|authcid|authzid") */ lua_call(ctxp->L, 3, 1); /* Get the result */ str = lua_tolstring(ctxp->L, -1, &len); if (str == NULL) ret = SASL_BADPROT; else if (len >= out_umax) ret = SASL_BUFOVER; else { memcpy(out_user, str, len + 1); *out_ulen = len; } /* Pop the result of the call off the stack */ lua_pop(ctxp->L, 1); if (ret == SASL_OK) set_context_user(context, out_user, *out_ulen); else set_context_user(context, NULL, 0); return ret; }
static void ngx_http_lua_clear_package_loaded(lua_State *L) { size_t len; u_char *p; dd("clear out package.loaded.* on the Lua land"); lua_getglobal(L, "package"); /* package */ lua_getfield(L, -1, "loaded"); /* package loaded */ lua_pushnil(L); /* package loaded nil */ while (lua_next(L, -2)) { /* package loaded key value */ lua_pop(L, 1); /* package loaded key */ p = (u_char *) lua_tolstring(L, -1, &len); #if 1 /* XXX work-around the "stack overflow" issue of LuaRocks * while unloading and reloading Lua modules */ if (len >= sizeof("luarocks") - 1 && ngx_strncmp(p, "luarocks", sizeof("luarocks") - 1) == 0) { goto done; } #endif switch (len) { case 2: if (p[0] == 'o' && p[1] == 's') { goto done; } if (p[0] == 'i' && p[1] == 'o') { goto done; } #if 0 if (ngx_strncmp(p, "_G", sizeof("_G") - 1) == 0) { goto done; } #endif break; case 3: if (ngx_strncmp(p, "bit", sizeof("bit") - 1) == 0) { goto done; } if (ngx_strncmp(p, "jit", sizeof("jit") - 1) == 0) { goto done; } if (ngx_strncmp(p, "ngx", sizeof("ngx") - 1) == 0) { goto done; } if (ngx_strncmp(p, "ndk", sizeof("ndk") - 1) == 0) { goto done; } break; case 4: if (ngx_strncmp(p, "math", sizeof("math") - 1) == 0) { goto done; } break; case 5: if (ngx_strncmp(p, "table", sizeof("table") - 1) == 0) { goto done; } if (ngx_strncmp(p, "debug", sizeof("table") - 1) == 0) { goto done; } break; case 6: if (ngx_strncmp(p, "string", sizeof("string") - 1) == 0) { goto done; } break; case 7: if (ngx_strncmp(p, "package", sizeof("package") - 1) == 0) { goto done; } if (ngx_strncmp(p, "jit.opt", sizeof("jit.opt") - 1) == 0) { goto done; } break; case 8: if (ngx_strncmp(p, "jit.util", sizeof("jit.util") - 1) == 0) { goto done; } break; case 9: if (ngx_strncmp(p, "coroutine", sizeof("coroutine") - 1) == 0) { goto done; } break; default: break; } dd("clearing package %s", p); lua_pushvalue(L, -1); /* package loaded key key */ lua_pushnil(L); /* package loaded key key nil */ lua_settable(L, -4); /* package loaded key */ done: continue; } /* package loaded */ lua_pop(L, 2); lua_newtable(L); lua_setglobal(L, "_G"); }
AV * plu_table_obj_to_array(pTHX_ plu_table_t *THIS, int recursive) { PLU_dSTACKASSERT; int table_stack_offset; lua_State *L; char *keystr; size_t keylen; SV *value_sv; int dopop; AV *RETVAL; I32 aryidx; L = THIS->L; PLU_ENTER_STACKASSERT(L); PLU_TABLE_PUSH_TO_STACK(*THIS); RETVAL = newAV(); sv_2mortal((SV *)RETVAL); table_stack_offset = lua_gettop(L); lua_pushnil(L); /* first key */ while (lua_next(L, table_stack_offset) != 0) { /* uses 'key' (at index -2) and 'value' (at index -1) */ /* Prepare key - cast to int if need be */ switch (lua_type(L, -2)) { case LUA_TSTRING: { SV *tmpsv; keystr = (char *)lua_tolstring(L, -2, &keylen); /* Using SV is not efficient, but may cause the perl warnings we want. * That in turn may cause Perl code to be run that can throw exceptions. * So we need to mortalize. Grmpf. */ tmpsv = newSVpvn(keystr, (STRLEN)keylen); sv_2mortal(tmpsv); aryidx = (I32)SvIV(tmpsv); SvREFCNT_dec(tmpsv); break; } case LUA_TNUMBER: { lua_Number n = lua_tonumber(L, -2); /* Don't change its type with lua_tointeger! */ aryidx = (I32)n; /* FIXME should this warn for actual truncation? */ break; } case LUA_TBOOLEAN: aryidx = lua_toboolean(L, -2); break; default: croak("Unsupported Lua type '%s' for Perl array indexes", lua_typename(L, lua_type(L, 02))); } /* Prepare value */ value_sv = plu_luaval_to_perl(aTHX_ L, -1, &dopop); if (recursive && SvROK(value_sv) && sv_derived_from(value_sv, "PLua::Table")) { AV *tmpa; tmpa = plu_table_obj_to_array(aTHX_ (plu_table_t *)SvIV(SvRV(value_sv)), recursive); SvREFCNT_dec(value_sv); value_sv = newRV_inc((SV *)tmpa); } (void)av_store(RETVAL, aryidx, value_sv); /* removes 'value' if not already done; keeps 'key' for next iteration */ if (dopop) lua_pop(L, 1); } lua_pop(L, 1); PLU_LEAVE_STACKASSERT(L); return RETVAL; }
int am_require(lua_State *L) { am_check_nargs(L, 1); char tmpbuf1[TMP_BUF_SZ]; char tmpbuf2[TMP_BUF_SZ]; size_t len; const char *modname = lua_tolstring(L, 1, &len); // check for string argument if (modname == NULL) { return luaL_error(L, "require expects a string as its single argument"); } // check module name not too long if (len > TMP_BUF_SZ - 10) { return luaL_error(L, "module name '%s' too long", modname); } // check if module has already been loaded lua_rawgeti(L, LUA_REGISTRYINDEX, AM_MODULE_TABLE); lua_pushvalue(L, 1); // module name lua_rawget(L, -2); if (!lua_isnil(L, -1)) { // already loaded, or busy loading lua_remove(L, -2); // module table return 1; } lua_pop(L, 1); // nil // create exports table and add to module table: lua_newtable(L); lua_pushvalue(L, 1); // module name lua_pushvalue(L, -2); // export table lua_rawset(L, -4); // set it // export table now on top // read in the module int sz; strncpy(tmpbuf1, modname, TMP_BUF_SZ); am_replchr(tmpbuf1, '.', AM_PATH_SEP); snprintf(tmpbuf2, TMP_BUF_SZ, "%s.lua", tmpbuf1); char *errmsg; void *buf = am_read_resource(tmpbuf2, &sz, &errmsg); if (buf == NULL) { lua_pushfstring(L, "unable to load module '%s': %s", modname, errmsg); free(errmsg); return lua_error(L); } // replace "#!" at start with "--" char *cbuf = (char*)buf; if (sz >= 2 && cbuf[0] == '#' && cbuf[1] == '!') { cbuf[0] = '-'; cbuf[1] = '-'; } // parse and load the module snprintf(tmpbuf2, TMP_BUF_SZ, "@%s.lua", tmpbuf1); int res = luaL_loadbuffer(L, (const char*)buf, sz, tmpbuf2); free(buf); if (res != 0) return lua_error(L); // pass export table as arg lua_pushvalue(L, -2); // export table lua_call(L, 1, 1); if (!lua_isnil(L, -1)) { // replace export table with returned value in module table lua_pushvalue(L, 1); // module name lua_pushvalue(L, -2); // returned value lua_rawset(L, -5); lua_remove(L, -2); // export table lua_remove(L, -2); // module table // return value now on top } else { lua_pop(L, 1); // nil lua_remove(L, -2); // module table // export table now on top } return 1; }