/* Experimental code, extends Lua * 02/02/2001 info@equi4.com */ #include #include #include #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #include #include #include #else #include #include #endif #include /* prototype */ LUALIB_API void xyzlib_open(lua_State *L); /* TODO: get rid of static ints, use closures instead */ static int xyzmemtag; /* xyz_Type - type of memory chunks */ enum { xyz_raw, xyz_heap, xyz_str, xyz_file }; /* xyz_Mem - userdata for each memmap */ typedef struct { char *ptr; size_t len; int type; union { FILE* fp; int ref; } u; } xyz_Mem; /* xyz_memhandle - type-safe conversion of userdata to xyz_Mem ptr */ static xyz_Mem* xyz_memhandle(lua_State *L, int f) { void *p = lua_touserdata(L, f); if (p == NULL || lua_tag(L, f) != xyzmemtag) lua_error(L, "wrong type - mem map expected"); return p; } /* xyz_mmclose - close memmap, cleaning up as appropriate */ static int xyz_mmclose(lua_State *L) { xyz_Mem *m = (xyz_Mem*) xyz_memhandle(L, -1); switch (m->type) { case xyz_heap: free(m->ptr); break; case xyz_str: lua_unref(L, m->u.ref); break; case xyz_file: #ifdef WIN32 UnmapViewOfFile(m->ptr); #else munmap(m->ptr, m->len); #endif fclose(m->u.fp); break; } m->type = xyz_raw; m->ptr = 0; m->len = 0; return 0; } /* xyz_newmem - create a new memmap, as userdata structure */ static xyz_Mem *xyz_newmem(lua_State *L, int t, char *p, size_t n) { xyz_Mem *m = (xyz_Mem*) lua_newuserdata(L, sizeof (xyz_Mem)); lua_settag(L, xyzmemtag); m->type = t; m->ptr = p; m->len = n; return m; /* also leaves new userdata on stack */ } /* xyz_mmraw - create a memmap from raw memory (dangerous) */ static int xyz_mmraw(lua_State *L) { void* ptr = (void*) luaL_check_long(L, 1); size_t len = luaL_check_long(L, 2); (void) xyz_newmem(L, xyz_raw, ptr, len); return 1; } /* xyz_mmheap - create a memmap from an allocated chunk of memory */ static int xyz_mmheap(lua_State *L) { size_t len = luaL_check_long(L, 1); (void) xyz_newmem(L, xyz_heap, malloc(len), len); return 1; } /* xyz_mmstr - create a memmap from a Lua string (shares memory) */ static int xyz_mmstr(lua_State *L) { size_t len; char *ptr = (char*) luaL_check_lstr(L, -1, &len); int ref = lua_ref(L, 1); xyz_Mem *m = xyz_newmem(L, xyz_str, ptr, len); m->u.ref = ref; return 1; } /* xyz_mmfile - create a memmap from a file, specified by name */ static int xyz_mmfile(lua_State *L) { char *ptr; size_t len; xyz_Mem *m; FILE *fp = fopen(luaL_check_string(L, 1), "rb"); if (fp == NULL) lua_error(L, "cannot open file"); fseek(fp, 0, SEEK_END); len = ftell(fp); #ifdef WIN32 { HANDLE h = CreateFileMapping((HANDLE) _get_osfhandle(_fileno(fp)), 0, PAGE_READONLY, 0, len, 0); ptr = h ? MapViewOfFile(h, FILE_MAP_READ, 0, 0, len) : NULL; } #else ptr = mmap(0, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0); #endif if (ptr == NULL) { fclose(fp); lua_error(L, "cannot map file"); } m = xyz_newmem(L, xyz_file, ptr, len); m->u.fp = fp; return 1; } /* xyz_mminfo - return type, address, and length of this memmap */ static int xyz_mminfo(lua_State *L) { xyz_Mem *m = xyz_memhandle(L, 1); if (m->len <= 0) return 0; lua_pushnumber(L, (long) m->ptr); lua_pushnumber(L, m->len); lua_pushnumber(L, m->type); return 3; } /* xyz_mmsub - return a sub-string copy made from this memmap */ static int xyz_mmsub(lua_State *L) { xyz_Mem *m = xyz_memhandle(L, 1); int i = luaL_opt_int(L, 2, 1); int j = luaL_opt_int(L, 3, -1); /* note: the following code also converts to 0-based [i..j) */ i += i < 0 ? m->len : -1; if (j < 0) j += m->len + 1; /* if (i < 0 || j > m->len || i > j) return 0; */ if (i < 0) i = 0; if (j > m->len) j = m->len; if (i > j) i = j; lua_pushlstring(L, m->ptr + i, j - i); return 1; } /* xyz_xyzlibvers - get at the library version info and such */ static int xyz_xyzlibvers(lua_State *L) { lua_pushstring(L, __DATE__); lua_pushnumber(L, 8); lua_pushnumber(L, xyzmemtag); return 4; } /* xyzlib - functions defined in this extension */ static struct luaL_reg xyzlib[] = { {"mmraw", xyz_mmraw}, {"mmheap", xyz_mmheap}, {"mmstr", xyz_mmstr}, {"mmfile", xyz_mmfile}, {"mmclose", xyz_mmclose}, {"mminfo", xyz_mminfo}, {"mmsub", xyz_mmsub}, {"xyzlibvers", xyz_xyzlibvers}, }; /* xyzlib_open - the one and only public entry point */ void xyzlib_open(lua_State *L) { xyzmemtag = lua_newtag(L); lua_pushcfunction(L, xyz_mmclose); lua_settagmethod(L, xyzmemtag, "gc"); luaL_openl(L, xyzlib); }