From 6ba597d46a93aaa9a17eb8a9fe8f3bcdedf686c0 Mon Sep 17 00:00:00 2001 From: pixel Date: Sat, 27 Nov 2004 21:01:20 +0000 Subject: Added dirent stuff to cd-tool --- MSVC/dirent/_mingw.h | 68 +++ MSVC/dirent/dirent.c | 316 ++++++++++ MSVC/dirent/dirent.h | 96 +++ include/BLua.h | 751 ++++++++++++------------ lib/BLua.cc | 1329 +++++++++++++++++++++--------------------- lib/lua/include/lualib.h | 5 +- lib/lua/src/LuaLib/ldirlib.c | 101 ++++ 7 files changed, 1628 insertions(+), 1038 deletions(-) create mode 100644 MSVC/dirent/_mingw.h create mode 100644 MSVC/dirent/dirent.c create mode 100644 MSVC/dirent/dirent.h create mode 100644 lib/lua/src/LuaLib/ldirlib.c diff --git a/MSVC/dirent/_mingw.h b/MSVC/dirent/_mingw.h new file mode 100644 index 0000000..e6fa7dd --- /dev/null +++ b/MSVC/dirent/_mingw.h @@ -0,0 +1,68 @@ +/* + * _mingw.h + * + * Mingw specific macros included by ALL include files. + * + * This file is part of the Mingw32 package. + * + * Contributors: + * Created by Mumit Khan + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __MINGW_H +#define __MINGW_H + +/* These are defined by the user (or the compiler) + to specify how identifiers are imported from a DLL. + + __DECLSPEC_SUPPORTED Defined if dllimport attribute is supported. + __MINGW_IMPORT The attribute definition to specify imported + variables/functions. + __MINGW32_VERSION Runtime version. + __MINGW32_MAJOR_VERSION Runtime major version. + __MINGW32_MINOR_VERSION Runtime minor version. + __MINGW32_BUILD_DATE Runtime build date. + + Other macros: + + __int64 define to be long long. Using a typedef can + tweak bugs in the C++ parser. + + All headers should include this first, and then use __DECLSPEC_SUPPORTED + to choose between the old ``__imp__name'' style or __MINGW_IMPORT + style declarations. */ + +#ifndef __GNUC__ +# define __MINGW_IMPORT __declspec(dllimport) +# define __DECLSPEC_SUPPORTED +#else /* __GNUC__ */ +# ifdef __declspec + /* note the extern at the end. This is needed to work around GCC's + limitations in handling dllimport attribute. */ +# define __MINGW_IMPORT __attribute__((dllimport)) extern +# define __DECLSPEC_SUPPORTED +# else +# undef __DECLSPEC_SUPPORTED +# undef __MINGW_IMPORT +# endif +# undef __int64 +# define __int64 long long +#endif /* __GNUC__ */ + +#define __MINGW32_VERSION 1.2 +#define __MINGW32_MAJOR_VERSION 1 +#define __MINGW32_MINOR_VERSION 2 + +#endif /* __MINGW_H */ + diff --git a/MSVC/dirent/dirent.c b/MSVC/dirent/dirent.c new file mode 100644 index 0000000..d062d63 --- /dev/null +++ b/MSVC/dirent/dirent.c @@ -0,0 +1,316 @@ +/* + * dirent.c + * + * Derived from DIRLIB.C by Matt J. Weinstein + * This note appears in the DIRLIB.H + * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Updated by Jeremy Bettis + * Significantly revised and rewinddir, seekdir and telldir added by Colin + * Peters + * + * $Revision: 1.1 $ + * $Author: pixel $ + * $Date: 2004-11-27 21:01:21 $ + * + */ + +#include +#include +#include +#include +#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include /* for GetFileAttributes */ + +#define SUFFIX "*" +#define SLASH "\\" + +/* + * opendir + * + * Returns a pointer to a DIR structure appropriately filled in to begin + * searching a directory. + */ +DIR * +opendir (const char *szPath) +{ + DIR *nd; + unsigned int rc; + + errno = 0; + + if (!szPath) + { + errno = EFAULT; + return (DIR *) 0; + } + + if (szPath[0] == '\0') + { + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Attempt to determine if the given path really is a directory. */ + rc = GetFileAttributes(szPath); + if (rc == -1) + { + /* call GetLastError for more error info */ + errno = ENOENT; + return (DIR *) 0; + } + if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) + { + /* Error, entry exists but not a directory. */ + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Allocate enough space to store DIR structure and the complete + * directory path given. */ + nd = (DIR *) malloc (sizeof (DIR) + strlen (szPath) + strlen (SLASH) + + strlen (SUFFIX)); + + if (!nd) + { + /* Error, out of memory. */ + errno = ENOMEM; + return (DIR *) 0; + } + + /* Create the search expression. */ + strcpy (nd->dd_name, szPath); + + /* Add on a slash if the path does not end with one. */ + if (nd->dd_name[0] != '\0' && + nd->dd_name[strlen (nd->dd_name) - 1] != '/' && + nd->dd_name[strlen (nd->dd_name) - 1] != '\\') + { + strcat (nd->dd_name, SLASH); + } + + /* Add on the search pattern */ + strcat (nd->dd_name, SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try + * to call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under + * Win32, and name simply points at the appropriate part of the + * findfirst_t structure. */ + nd->dd_dir.d_ino = 0; + nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + nd->dd_dir.d_name = nd->dd_dta.name; + + return nd; +} + + +/* + * readdir + * + * Return a pointer to a dirent structure filled with the information on the + * next entry in the directory. + */ +struct dirent * +readdir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return (struct dirent *) 0; + } + + if (dirp->dd_dir.d_name != dirp->dd_dta.name) + { + /* The structure does not seem to be set up correctly. */ + errno = EINVAL; + return (struct dirent *) 0; + } + + if (dirp->dd_stat < 0) + { + /* We have already returned all files in the directory + * (or the structure has an invalid dd_stat). */ + return (struct dirent *) 0; + } + else if (dirp->dd_stat == 0) + { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta)); + + if (dirp->dd_handle == -1) + { + /* Whoops! Seems there are no files in that + * directory. */ + dirp->dd_stat = -1; + } + else + { + dirp->dd_stat = 1; + } + } + else + { + /* Get the next search entry. */ + if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) + { + /* We are off the end or otherwise error. */ + _findclose (dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Update the status to indicate the correct + * number. */ + dirp->dd_stat++; + } + } + + if (dirp->dd_stat > 0) + { + /* Successfully got an entry. Everything about the file is + * already appropriately filled in except the length of the + * file name. */ + dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name); + return &dirp->dd_dir; + } + + return (struct dirent *) 0; +} + + +/* + * closedir + * + * Frees up resources allocated by opendir. + */ +int +closedir (DIR * dirp) +{ + int rc; + + errno = 0; + rc = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + + if (dirp->dd_handle != -1) + { + rc = _findclose (dirp->dd_handle); + } + + /* Delete the dir structure. */ + free (dirp); + + return rc; +} + +/* + * rewinddir + * + * Return to the beginning of the directory "stream". We simply call findclose + * and then reset things like an opendir. + */ +void +rewinddir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + + dirp->dd_handle = -1; + dirp->dd_stat = 0; +} + +/* + * telldir + * + * Returns the "position" in the "directory stream" which can be used with + * seekdir to go back to an old entry. We simply return the value in stat. + */ +long +telldir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + return dirp->dd_stat; +} + +/* + * seekdir + * + * Seek to an entry previously returned by telldir. We rewind the directory + * and call readdir repeatedly until either dd_stat is the position number + * or -1 (off the end). This is not perfect, in that the directory may + * have changed while we weren't looking. But that is probably the case with + * any such system. + */ +void +seekdir (DIR * dirp, long lPos) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (lPos < -1) + { + /* Seeking to an invalid position. */ + errno = EINVAL; + return; + } + else if (lPos == -1) + { + /* Seek past end. */ + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Rewind and read forward to the appropriate index. */ + rewinddir (dirp); + + while ((dirp->dd_stat < lPos) && readdir (dirp)) + ; + } +} diff --git a/MSVC/dirent/dirent.h b/MSVC/dirent/dirent.h new file mode 100644 index 0000000..8c4a657 --- /dev/null +++ b/MSVC/dirent/dirent.h @@ -0,0 +1,96 @@ +/* + * DIRENT.H (formerly DIRLIB.H) + * + * by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Because I have heard that this feature (opendir, readdir, closedir) + * it so useful for programmers coming from UNIX or attempting to port + * UNIX code, and because it is reasonably light weight, I have included + * it in the Mingw32 package. I have also added an implementation of + * rewinddir, seekdir and telldir. + * - Colin Peters + * + * This code is distributed in the hope that is will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includeds but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.1 $ + * $Author: pixel $ + * $Date: 2004-11-27 21:01:21 $ + * + */ + +#ifndef __STRICT_ANSI__ + +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + +/* All the headers include this file. */ +#include <_mingw.h> + +#include + +#ifndef RC_INVOKED + +#ifdef __cplusplus +extern "C" { +#endif + +struct dirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the + * finddata_t structure in the DIR. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + short dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; +} DIR; + + +DIR* opendir (const char*); +struct dirent* readdir (DIR*); +int closedir (DIR*); +void rewinddir (DIR*); +long telldir (DIR*); +void seekdir (DIR*, long); + +#ifdef __cplusplus +} +#endif + +#endif /* Not RC_INVOKED */ + +#endif /* Not _DIRENT_H_ */ + +#endif /* Not __STRICT_ANSI__ */ + diff --git a/include/BLua.h b/include/BLua.h index a0daa59..52918ee 100644 --- a/include/BLua.h +++ b/include/BLua.h @@ -1,375 +1,376 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: BLua.h,v 1.17 2004-07-23 13:08:22 pixel Exp $ */ - -#ifndef __BLUA_H__ -#define __BLUA_H__ - -struct lua_State; - -extern "C" { - void do_lua_lock(lua_State *); - void do_lua_unlock(lua_State *); -} - -#define lua_lock(L) do_lua_lock(L) -#define lua_unlock(L) do_lua_unlock(L) - -#include -#include -#include -#include - -class Lua : public Base { - public: - Lua(); - Lua(const Lua &) throw (GeneralException); - virtual ~Lua(); - void open_base(); - void open_table(); - void open_io(); - void open_string(); - void open_math(); - void open_debug(); - void declarefunc(const String &, lua_CFunction, int = LUA_GLOBALSINDEX); - void call(const String &, int = LUA_GLOBALSINDEX, int = 0, int = 0); - void call(int = 0, int = 0); - void push(); - void push(lua_Number); - void push(const String &); - void push(bool); - void push(char *, int size = -1); - void push(void *); - void push(lua_CFunction, int = 0); - void pop(int = 1); - void newtable(); - void * newuser(size_t); - void settable(int = -3, bool raw = false); - void gettable(int = -2, bool raw = false); - void setvar(); - int gettop(); - void error(const String &); - int type(int = -1); - bool isnil(int = -1); - bool isboolean(int = -1); - bool isnumber(int = -1); - bool isstring(int = -1); - bool istable(int = -1); - bool isfunction(int = -1); - bool iscfunction(int = -1); - bool isuserdata(int = -1); - bool islightuserdata(int = -1); - bool toboolean(int = -1); - lua_Number tonumber(int = -1); - String tostring(int = -1); - lua_CFunction tocfunction(int = -1); - void * touserdata(int = -1); - Lua * tothread(int = -1); - void load(Handle *, bool docall = true) throw (GeneralException); - void dump(Handle *, bool strip = true); - Lua * thread(); - int yield(int nargs = 0); - int resume(int nresults = 0); - static Lua * find(lua_State *) throw (GeneralException); - void showerror(); - int getmetatable(int = -1); - int setmetatable(int = -2); - int sethook(lua_Hook func, int mask, int count); - - void do_break(); - - virtual void lock() {} - virtual void unlock() {} - private: - Lua(lua_State *); - lua_State * L; - static std::map lualist; -}; - -class LuaObject : public Base { - public: - LuaObject() : wantdestruct(false), pushed(false) {} - virtual void push(Lua *) throw (GeneralException); - static void * getme(Lua *, int = 1); - void pushdestruct(Lua *) throw (GeneralException); - protected: - virtual void pushmembers(Lua *) = 0; - void pushme(Lua *, void *, bool = true); - static void pushit(Lua *, const String &, lua_CFunction); - static void pushmeta(Lua *, const String &, lua_CFunction); - bool wantdestruct, pushed; -}; - -class LuaException : public GeneralException { - public: - LuaException(String); - protected: - LuaException(); -}; - -enum Lua_types_t { - LUA_OBJECT = 0x01, - LUA_TABLE = 0x02, - LUA_BOOLEAN = 0x04, - LUA_NUMBER = 0x08, - LUA_STRING = 0x10, - LUA_FUNCTION = 0x20, - LUA_NIL = 0x40, - LUA_ANY = 0x7f, -}; - -#define MAX_TYPE 7 - -#define MAXARGS 32 - -struct lua_functypes_t { - int number; - char * name; - int minargs, maxargs; - int argtypes[MAXARGS]; -}; - -#define DECLARE_METHOD(classname, enumvar) static int method_##enumvar(lua_State * L) { \ - return LuaHelpers::method_multiplex( \ - enumvar, \ - L, \ - sLua_##classname::classname##_proceed, \ - 0, \ - classname##_methods, \ - true); \ - } - -#define DECLARE_FUNCTION(classname, enumvar) static int function_##enumvar(lua_State * L) { \ - return LuaHelpers::method_multiplex( \ - enumvar, \ - L, \ - 0, \ - sLua_##classname::classname##_proceed_statics, \ - classname##_functions, \ - false); \ - } - -#define PUSH_METHOD(classname, enumvar) pushit( \ - L, \ - classname##_methods[enumvar].name, \ - sLua_##classname::method_##enumvar) - -#define PUSH_METAMETHOD(classname, enumvar) pushmeta( \ - L, \ - String("__") + classname##_methods[enumvar].name, \ - sLua_##classname::method_##enumvar) - -#define PUSH_FUNCTION(classname, enumvar) L->declarefunc( \ - classname##_functions[enumvar].name, \ - sLua_##classname::function_##enumvar) - - -#define CHECK_METHODS(classname) { \ - int i = 0; \ - while (classname##_methods[i].number != -1) { \ - if (i != classname##_methods[i].number) { \ - throw GeneralException("Datas of " #classname "_methods inconsistants!"); \ - } \ - i++; \ - } \ -} - -#define CHECK_FUNCTIONS(classname) { \ - int i = 0; \ - while (classname##_functions[i].number != -1) { \ - if (i != classname##_functions[i].number) { \ - throw GeneralException("Datas of " #classname "_functions inconsistants!"); \ - } \ - i++; \ - } \ -} - -#include - -template -class LuaHelpers : public Base { - public: - static int method_multiplex(int caller, lua_State * _L, int (*proceed)(Lua * L, int n, T * obj, int caller), int (*proceed_static)(Lua * L, int n, int caller), lua_functypes_t * tab, bool method) { - Lua * L = Lua::find(_L); - int add = method ? 1 : 0; - int n = L->gettop() - add; - T * obj = 0; - int i, j, mask; - bool invalid = false, arg_valid; - - if (method) - obj = (T *) LuaObject::getme(L); - - if ((n < tab[caller].minargs) || (n > tab[caller].maxargs)) { - invalid = true; - } else { - for (i = 0; i < tab[caller].maxargs && !invalid; i++) { - if (n >= (i + 1)) { - arg_valid = false; - for (j = 0; j < MAX_TYPE && !arg_valid; j++) { - mask = 1 << j; - if (tab[caller].argtypes[i] & mask) { - switch(mask) { - case LUA_OBJECT: - if (L->istable(i + 1 + add)) { - L->push("__obj"); - L->gettable(i + 1 + add); - arg_valid = L->isuserdata(); - L->pop(); - } else { - arg_valid = L->isnil(i + 1 + add); - } - break; - case LUA_TABLE: - arg_valid = L->istable(i + 1 + add); - break; - case LUA_BOOLEAN: - arg_valid = L->isboolean(i + 1 + add); - break; - case LUA_NUMBER: - arg_valid = L->isnumber(i + 1 + add); - break; - case LUA_STRING: - arg_valid = L->isstring(i + 1 + add); - break; - case LUA_FUNCTION: - arg_valid = L->isfunction(i + 1 + add); - break; - case LUA_NIL: - arg_valid = L->isnil(i + 1 + add); - break; - } - } - } - invalid = !arg_valid; - } - } - } - - if (invalid) { - if (method) { - L->error(String("Invalid arguments to method `") + typeid(T).name() + "::" + tab[caller].name + "'"); - } else { - L->error(String("Invalid arguments to function `") + typeid(T).name() + "::" + tab[caller].name + "'"); - } - } - - if (method) { - return proceed(L, n, obj, caller); - } else { - return proceed_static(L, n, caller); - } - } -}; - - - /*******************************\ -|** Let's have a sample of use **| - \*******************************/ - -#ifdef THIS_IS_A_SAMPLE_WHICH_DOES_NOT_COMPILE -Luacdfile::Luacdfile(cdfile * h) : LuaHandle(h) { } - -enum cdfile_methods_t { - CDFILE_XXX = 0, - CDFILE_YYY -}; - -enum cdfile_functions_t { - CDFILE_NEWCDFILE = 0, -}; - -struct lua_functypes_t cdutils_methods[] = { - { CDFILE_XXX, "xxx", 1, 1, {LUA_OBJECT} }, - { CDFILE_YYY, "yyy", 0, 2, {LUA_NUMBER, LUA_NUMBER} }, - { -1, 0, 0, 0, 0 } -}; - -struct lua_functypes_t cdfile_functions[] = { - { CDFILE_NEWCDFILE, "cdfile", 1, 4, {LUA_OBJECT, LUA_ANY, LUA_NUMBER, LUA_NUMBER} }, - { -1, 0, 0, 0, 0 } -}; - -class sLua_cdfile : public Base { - public: - static int newcdfile(lua_State * L); - DECLARE_METHOD(cdfile, CDFILE_XXX); - DECLARE_METHOD(cdfile, CDFILE_YYY); - DECLARE_FUNCTION(cdfile, CDFILE_NEWCDFILE); - private: - static int cdfile_proceed(Lua * L, int n, cdfile * obj, int caller); - static int cdfile_proceed_statics(Lua * L, int n, int caller); -}; - -void Luacdfile::pushmembers(Lua * L) { - { - LuaHandle::pushmembers(L); - or - pushme(L, SomeObject); - } - PUSH_METHOD(cdfile, CDFILE_XXX); - PUSH_METHOD(cdfile, CDFILE_YYY); -} - -void Luacdfile::pushstatics(Lua * L) { - CHECK_METHODS(cdfile); - CHECK_FUNCTIONS(cdfile); - - PUSH_FUNCTION(cdfile, CDFILE_NEWCDFILE); -} - -int sLua_cdfile::cdfile_proceed(Lua * L, int n, cdfile * cdfile, int caller) { - int r = 0; - SomeObj * obj; - int arg1 = DEFAULT1, arg2 = DEFAULT2; - - switch(caller) { - case CDFILE_XXX: - obj = (SomeObj *) LuaObject::getme(L, 2); - cdfile->xxx(obj); - break; - case CDFILE_YYY: - if (n >= 1) - arg1 = L->tonumber(2); - if (n >= 2) - arg2 = L->tonumber(3); - L->push((lua_Number) cdfile->yyy(arg1, arg2)); - r = 1; - break; - } - - return r; -} - -int sLua_cdfile::cdfile_proceed_statics(Lua * L, int n, int caller) { - int r = 0; - - switch(caller) { - case CDFILE_NEWCDFILE: - /****TODO****/ - break; - } - - return r; -} - -#endif - -#endif +/* + * Baltisot + * Copyright (C) 1999-2003 Nicolas "Pixel" Noble + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id: BLua.h,v 1.18 2004-11-27 21:01:20 pixel Exp $ */ + +#ifndef __BLUA_H__ +#define __BLUA_H__ + +struct lua_State; + +extern "C" { + void do_lua_lock(lua_State *); + void do_lua_unlock(lua_State *); +} + +#define lua_lock(L) do_lua_lock(L) +#define lua_unlock(L) do_lua_unlock(L) + +#include +#include +#include +#include + +class Lua : public Base { + public: + Lua(); + Lua(const Lua &) throw (GeneralException); + virtual ~Lua(); + void open_base(); + void open_table(); + void open_io(); + void open_string(); + void open_math(); + void open_debug(); + void open_dir(); + void declarefunc(const String &, lua_CFunction, int = LUA_GLOBALSINDEX); + void call(const String &, int = LUA_GLOBALSINDEX, int = 0, int = 0); + void call(int = 0, int = 0); + void push(); + void push(lua_Number); + void push(const String &); + void push(bool); + void push(char *, int size = -1); + void push(void *); + void push(lua_CFunction, int = 0); + void pop(int = 1); + void newtable(); + void * newuser(size_t); + void settable(int = -3, bool raw = false); + void gettable(int = -2, bool raw = false); + void setvar(); + int gettop(); + void error(const String &); + int type(int = -1); + bool isnil(int = -1); + bool isboolean(int = -1); + bool isnumber(int = -1); + bool isstring(int = -1); + bool istable(int = -1); + bool isfunction(int = -1); + bool iscfunction(int = -1); + bool isuserdata(int = -1); + bool islightuserdata(int = -1); + bool toboolean(int = -1); + lua_Number tonumber(int = -1); + String tostring(int = -1); + lua_CFunction tocfunction(int = -1); + void * touserdata(int = -1); + Lua * tothread(int = -1); + void load(Handle *, bool docall = true) throw (GeneralException); + void dump(Handle *, bool strip = true); + Lua * thread(); + int yield(int nargs = 0); + int resume(int nresults = 0); + static Lua * find(lua_State *) throw (GeneralException); + void showerror(); + int getmetatable(int = -1); + int setmetatable(int = -2); + int sethook(lua_Hook func, int mask, int count); + + void do_break(); + + virtual void lock() {} + virtual void unlock() {} + private: + Lua(lua_State *); + lua_State * L; + static std::map lualist; +}; + +class LuaObject : public Base { + public: + LuaObject() : wantdestruct(false), pushed(false) {} + virtual void push(Lua *) throw (GeneralException); + static void * getme(Lua *, int = 1); + void pushdestruct(Lua *) throw (GeneralException); + protected: + virtual void pushmembers(Lua *) = 0; + void pushme(Lua *, void *, bool = true); + static void pushit(Lua *, const String &, lua_CFunction); + static void pushmeta(Lua *, const String &, lua_CFunction); + bool wantdestruct, pushed; +}; + +class LuaException : public GeneralException { + public: + LuaException(String); + protected: + LuaException(); +}; + +enum Lua_types_t { + LUA_OBJECT = 0x01, + LUA_TABLE = 0x02, + LUA_BOOLEAN = 0x04, + LUA_NUMBER = 0x08, + LUA_STRING = 0x10, + LUA_FUNCTION = 0x20, + LUA_NIL = 0x40, + LUA_ANY = 0x7f, +}; + +#define MAX_TYPE 7 + +#define MAXARGS 32 + +struct lua_functypes_t { + int number; + char * name; + int minargs, maxargs; + int argtypes[MAXARGS]; +}; + +#define DECLARE_METHOD(classname, enumvar) static int method_##enumvar(lua_State * L) { \ + return LuaHelpers::method_multiplex( \ + enumvar, \ + L, \ + sLua_##classname::classname##_proceed, \ + 0, \ + classname##_methods, \ + true); \ + } + +#define DECLARE_FUNCTION(classname, enumvar) static int function_##enumvar(lua_State * L) { \ + return LuaHelpers::method_multiplex( \ + enumvar, \ + L, \ + 0, \ + sLua_##classname::classname##_proceed_statics, \ + classname##_functions, \ + false); \ + } + +#define PUSH_METHOD(classname, enumvar) pushit( \ + L, \ + classname##_methods[enumvar].name, \ + sLua_##classname::method_##enumvar) + +#define PUSH_METAMETHOD(classname, enumvar) pushmeta( \ + L, \ + String("__") + classname##_methods[enumvar].name, \ + sLua_##classname::method_##enumvar) + +#define PUSH_FUNCTION(classname, enumvar) L->declarefunc( \ + classname##_functions[enumvar].name, \ + sLua_##classname::function_##enumvar) + + +#define CHECK_METHODS(classname) { \ + int i = 0; \ + while (classname##_methods[i].number != -1) { \ + if (i != classname##_methods[i].number) { \ + throw GeneralException("Datas of " #classname "_methods inconsistants!"); \ + } \ + i++; \ + } \ +} + +#define CHECK_FUNCTIONS(classname) { \ + int i = 0; \ + while (classname##_functions[i].number != -1) { \ + if (i != classname##_functions[i].number) { \ + throw GeneralException("Datas of " #classname "_functions inconsistants!"); \ + } \ + i++; \ + } \ +} + +#include + +template +class LuaHelpers : public Base { + public: + static int method_multiplex(int caller, lua_State * _L, int (*proceed)(Lua * L, int n, T * obj, int caller), int (*proceed_static)(Lua * L, int n, int caller), lua_functypes_t * tab, bool method) { + Lua * L = Lua::find(_L); + int add = method ? 1 : 0; + int n = L->gettop() - add; + T * obj = 0; + int i, j, mask; + bool invalid = false, arg_valid; + + if (method) + obj = (T *) LuaObject::getme(L); + + if ((n < tab[caller].minargs) || (n > tab[caller].maxargs)) { + invalid = true; + } else { + for (i = 0; i < tab[caller].maxargs && !invalid; i++) { + if (n >= (i + 1)) { + arg_valid = false; + for (j = 0; j < MAX_TYPE && !arg_valid; j++) { + mask = 1 << j; + if (tab[caller].argtypes[i] & mask) { + switch(mask) { + case LUA_OBJECT: + if (L->istable(i + 1 + add)) { + L->push("__obj"); + L->gettable(i + 1 + add); + arg_valid = L->isuserdata(); + L->pop(); + } else { + arg_valid = L->isnil(i + 1 + add); + } + break; + case LUA_TABLE: + arg_valid = L->istable(i + 1 + add); + break; + case LUA_BOOLEAN: + arg_valid = L->isboolean(i + 1 + add); + break; + case LUA_NUMBER: + arg_valid = L->isnumber(i + 1 + add); + break; + case LUA_STRING: + arg_valid = L->isstring(i + 1 + add); + break; + case LUA_FUNCTION: + arg_valid = L->isfunction(i + 1 + add); + break; + case LUA_NIL: + arg_valid = L->isnil(i + 1 + add); + break; + } + } + } + invalid = !arg_valid; + } + } + } + + if (invalid) { + if (method) { + L->error(String("Invalid arguments to method `") + typeid(T).name() + "::" + tab[caller].name + "'"); + } else { + L->error(String("Invalid arguments to function `") + typeid(T).name() + "::" + tab[caller].name + "'"); + } + } + + if (method) { + return proceed(L, n, obj, caller); + } else { + return proceed_static(L, n, caller); + } + } +}; + + + /*******************************\ +|** Let's have a sample of use **| + \*******************************/ + +#ifdef THIS_IS_A_SAMPLE_WHICH_DOES_NOT_COMPILE +Luacdfile::Luacdfile(cdfile * h) : LuaHandle(h) { } + +enum cdfile_methods_t { + CDFILE_XXX = 0, + CDFILE_YYY +}; + +enum cdfile_functions_t { + CDFILE_NEWCDFILE = 0, +}; + +struct lua_functypes_t cdutils_methods[] = { + { CDFILE_XXX, "xxx", 1, 1, {LUA_OBJECT} }, + { CDFILE_YYY, "yyy", 0, 2, {LUA_NUMBER, LUA_NUMBER} }, + { -1, 0, 0, 0, 0 } +}; + +struct lua_functypes_t cdfile_functions[] = { + { CDFILE_NEWCDFILE, "cdfile", 1, 4, {LUA_OBJECT, LUA_ANY, LUA_NUMBER, LUA_NUMBER} }, + { -1, 0, 0, 0, 0 } +}; + +class sLua_cdfile : public Base { + public: + static int newcdfile(lua_State * L); + DECLARE_METHOD(cdfile, CDFILE_XXX); + DECLARE_METHOD(cdfile, CDFILE_YYY); + DECLARE_FUNCTION(cdfile, CDFILE_NEWCDFILE); + private: + static int cdfile_proceed(Lua * L, int n, cdfile * obj, int caller); + static int cdfile_proceed_statics(Lua * L, int n, int caller); +}; + +void Luacdfile::pushmembers(Lua * L) { + { + LuaHandle::pushmembers(L); + or + pushme(L, SomeObject); + } + PUSH_METHOD(cdfile, CDFILE_XXX); + PUSH_METHOD(cdfile, CDFILE_YYY); +} + +void Luacdfile::pushstatics(Lua * L) { + CHECK_METHODS(cdfile); + CHECK_FUNCTIONS(cdfile); + + PUSH_FUNCTION(cdfile, CDFILE_NEWCDFILE); +} + +int sLua_cdfile::cdfile_proceed(Lua * L, int n, cdfile * cdfile, int caller) { + int r = 0; + SomeObj * obj; + int arg1 = DEFAULT1, arg2 = DEFAULT2; + + switch(caller) { + case CDFILE_XXX: + obj = (SomeObj *) LuaObject::getme(L, 2); + cdfile->xxx(obj); + break; + case CDFILE_YYY: + if (n >= 1) + arg1 = L->tonumber(2); + if (n >= 2) + arg2 = L->tonumber(3); + L->push((lua_Number) cdfile->yyy(arg1, arg2)); + r = 1; + break; + } + + return r; +} + +int sLua_cdfile::cdfile_proceed_statics(Lua * L, int n, int caller) { + int r = 0; + + switch(caller) { + case CDFILE_NEWCDFILE: + /****TODO****/ + break; + } + + return r; +} + +#endif + +#endif diff --git a/lib/BLua.cc b/lib/BLua.cc index 1c125a2..9366dd8 100644 --- a/lib/BLua.cc +++ b/lib/BLua.cc @@ -1,662 +1,667 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: BLua.cc,v 1.20 2004-07-23 13:08:23 pixel Exp $ */ - -#include "BLua.h" -#include - -#ifndef BUFFERSIZE -#define BUFFERSIZE 2048 -#endif - - - -extern "C" { - void do_lua_lock(lua_State * _L) { - Lua * L; - try { - L = Lua::find(_L); - } catch (GeneralException e) { - return; - } - L->lock(); - } - - void do_lua_unlock(lua_State * _L) { - Lua * L; - try { - L = Lua::find(_L); - } catch (GeneralException e) { - return; - } - L->unlock(); - } -} - -class LuaStatics : public Base { - public: - static const char * getF(lua_State *, void *, size_t *); - static int putF(lua_State *, const void *, size_t, void *); - static int luapanic(lua_State *); - static int trueluapanic(lua_State *) throw(GeneralException); - static int collector(lua_State *); - static int destructor(lua_State *); - - static int andB(lua_State *); - static int orB(lua_State *); - static int xorB(lua_State *); - static int notB(lua_State *); - static int hex(lua_State *); - static int shl(lua_State *); - static int shr(lua_State *); -}; - -std::map Lua::lualist; - -int LuaStatics::luapanic(lua_State * L) { - return trueluapanic(L); -} - -int LuaStatics::trueluapanic(lua_State * L) throw (GeneralException) { - Lua::find(L)->showerror(); - throw LuaException("Error running Lua code, bailing out."); -} - -int LuaStatics::andB(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Uint32 a, b; - - if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { - L->error("Incorrect arguments to function `andB'"); - } - - a = L->tonumber(1); - b = L->tonumber(2); - - L->push((lua_Number) (a & b)); - - return 1; -} - -int LuaStatics::orB(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Uint32 a, b; - - if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { - L->error("Incorrect arguments to function `orB'"); - } - - a = L->tonumber(1); - b = L->tonumber(2); - - L->push((lua_Number) (a | b)); - - return 1; -} - -int LuaStatics::xorB(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Uint32 a, b; - - if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { - L->error("Incorrect arguments to function `xorB'"); - } - - a = L->tonumber(1); - b = L->tonumber(2); - - L->push((lua_Number) (a ^ b)); - - return 1; -} - -int LuaStatics::notB(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Uint32 x; - - if ((n != 1) && !L->isnumber()) { - L->error("Incorrect arguments to function `notB'"); - } - - x = L->tonumber(); - - L->push((lua_Number) (~x)); - - return 1; -} - -int LuaStatics::shl(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Uint32 a, b; - - if ((n > 2) && !L->isnumber(1) && ((n == 2) && !L->isnumber(2))) { - L->error("Incorrect arguments to function `shl'"); - } - - a = L->tonumber(1); - if (n == 2) - b = L->tonumber(2); - else - b = 1; - - L->push((lua_Number) (a << b)); - - return 1; -} - -int LuaStatics::shr(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Uint32 a, b; - - if ((n > 2) && !L->isnumber(1) && ((n == 2) && !L->isnumber(2))) { - L->error("Incorrect arguments to function `shr'"); - } - - a = L->tonumber(1); - if (n == 2) - b = L->tonumber(2); - else - b = 1; - - L->push((lua_Number) (a >> b)); - - return 1; -} - -int LuaStatics::hex(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - int x; - String r; - - if (((n != 1) || (n != 2)) && !L->isnumber(1) && ((n == 2) && !L->isstring(2))) { - L->error("Incorrect arguments to function `hex'"); - } - - x = L->tonumber(1); - String fmt = n == 2 ? L->tostring() : "%02x"; - r.set(fmt.to_charp(), x); - - L->push(r); - - return 1; -} - -Lua::Lua() : L(lua_open()) { - lua_atpanic(L, LuaStatics::luapanic); - lualist[L] = this; - - declarefunc("andB", LuaStatics::andB); - declarefunc("orB", LuaStatics::orB); - declarefunc("xorB", LuaStatics::xorB); - declarefunc("notB", LuaStatics::notB); - declarefunc("shl", LuaStatics::shl); - declarefunc("shr", LuaStatics::shr); - declarefunc("hex", LuaStatics::hex); -} - -Lua::Lua(lua_State * _L) : L(_L) { - lua_atpanic(L, LuaStatics::luapanic); - lualist[L] = this; -} - -Lua::~Lua() { - lua_setgcthreshold(L, 0); - lua_close(L); -} - -Lua::Lua(const Lua & l) throw (GeneralException) { - throw GeneralException("Error: can't duplicate a Lua object."); -} - -void Lua::open_base() { - luaopen_base(L); - lua_pop(L, 1); -} - -void Lua::open_table() { - luaopen_table(L); - lua_pop(L, 1); -} - -void Lua::open_io() { - luaopen_io(L); - lua_pop(L, 1); -} - -void Lua::open_string() { - luaopen_string(L); - lua_pop(L, 1); -} - -void Lua::open_math() { - luaopen_math(L); - lua_pop(L, 1); -} - -void Lua::open_debug() { - luaopen_debug(L); - lua_pop(L, 1); -} - -void Lua::declarefunc(const String & name, lua_CFunction f, int i) { - lua_pushstring(L, name.to_charp()); - lua_pushcfunction(L, f); - lua_settable(L, i); -} - -void Lua::call(const String & f, int i, int nargs, int nresults) { - lua_pushstring(L, f.to_charp()); - lua_gettable(L, i); - lua_insert(L, -1 - nargs - nresults); - lua_call(L, nargs, nresults); -} - -void Lua::call(int nargs, int nresults) { - lua_call(L, nargs, nresults); -} - -void Lua::push() { - lua_pushnil(L); -} - -void Lua::push(lua_Number n) { - lua_pushnumber(L, n); -} - -void Lua::push(const String & s) { - lua_pushlstring(L, s.to_charp(), s.strlen()); -} - -void Lua::push(bool b) { - lua_pushboolean(L, b); -} - -void Lua::push(char * s, int size) { - if (size < 0) { - lua_pushstring(L, s); - } else { - lua_pushlstring(L, s, size); - } -} - -void Lua::push(void * p) { - lua_pushlightuserdata(L, p); -} - -void Lua::push(lua_CFunction f, int n) { - lua_pushcclosure(L, f, n); -} - -void Lua::pop(int n) { - lua_pop(L, n); -} - -void Lua::newtable() { - lua_newtable(L); -} - -void * Lua::newuser(size_t s) { - return lua_newuserdata(L, s); -} - -void Lua::settable(int i, bool raw) { - if (raw) { - lua_rawset(L, i); - } else { - lua_settable(L, i); - } -} - -void Lua::gettable(int i, bool raw) { - if (raw) { - lua_rawget(L, i); - } else { - lua_gettable(L, i); - } -} - -void Lua::setvar() { - lua_settable(L, LUA_GLOBALSINDEX); -} - -int Lua::gettop() { - return lua_gettop(L); -} - -void Lua::error(const String & msg) { - push(msg); - lua_error(L); -} - -int Lua::type(int i) { - return lua_type(L, i); -} - -bool Lua::isnil(int i) { - return lua_isnil(L, i); -} - -bool Lua::isboolean(int i) { - return lua_isboolean(L, i); -} - -bool Lua::isnumber(int i) { - return lua_isnumber(L, i); -} - -bool Lua::isstring(int i) { - return lua_isstring(L, i); -} - -bool Lua::istable(int i) { - return lua_istable(L, i); -} - -bool Lua::isfunction(int i) { - return lua_isfunction(L, i); -} - -bool Lua::iscfunction(int i) { - return lua_iscfunction(L, i); -} - -bool Lua::isuserdata(int i) { - return lua_isuserdata(L, i); -} - -bool Lua::islightuserdata(int i) { - return lua_islightuserdata(L, i); -} - -bool Lua::toboolean(int i) { - return lua_toboolean(L, i); -} - -lua_Number Lua::tonumber(int i) { - return lua_tonumber(L, i); -} - -String Lua::tostring(int i) { - if (isnil(i)) - return String(); - return String(lua_tostring(L, i)); -} - -lua_CFunction Lua::tocfunction(int i) { - return lua_tocfunction(L, i); -} - -void * Lua::touserdata(int i) { - return lua_touserdata(L, i); -} - -Lua * Lua::tothread(int i) { - return find(lua_tothread(L, i)); -} - -struct LoadF { - Handle * f; - char buff[BUFFERSIZE]; -}; - -const char * LuaStatics::getF(lua_State * L, void * ud, size_t * size) { - LoadF *lf = (LoadF *)ud; - (void)L; - - *size = lf->f->read(lf->buff, BUFFERSIZE); - return (*size > 0) ? lf->buff : NULL; -} - -struct DumpF { - Handle * f; -}; - -int LuaStatics::putF(lua_State * L, const void * p, size_t size, void * ud) { - DumpF *lf = (DumpF *)ud; - (void)L; - - return lf->f->write(p, size) == size; -} - -void Lua::load(Handle * h, bool docall) throw (GeneralException) { - LoadF lf; - int status; - - lf.f = h; - - status = lua_load(L, LuaStatics::getF, &lf, h->GetName().to_charp()); - - if (status) { - showerror(); - throw LuaException("Error loading lua chunk from Handle `" + h->GetName() + "'"); - } - - if (docall) - call(); -} - -extern "C" void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void * uD); - -void Lua::dump(Handle * h, bool strip) { - DumpF lf; - - lf.f = h; - - luacmain(L, strip, LuaStatics::putF, &lf); -} - -Lua * Lua::thread() { - return new Lua(lua_newthread(L)); -} - -int Lua::yield(int nargs) { - return lua_yield(L, nargs); -} - -int Lua::resume(int nresults) { - return lua_resume(L, nresults); -} - -Lua * Lua::find(lua_State * _L) throw (GeneralException) { - std::map::iterator i; - - if ((i = lualist.find(_L)) == lualist.end()) { - throw GeneralException("Unable to find the Lua object for this context"); - } - - return i->second; -} - -void Lua::showerror() { - int n = lua_gettop(L); - int i; - String t; - - printm(M_ERROR, "Lua object: Got an LUA error\n"); - printm(M_ERROR, "Inspecting LUA stack\n"); - - if (n == 0) { - printm(M_ERROR, "Stack empty\n"); - return; - } - - for (i = 1; i <= n; i++) { - switch(lua_type(L, i)) { - case LUA_TNONE: - t = "Invalid"; - break; - case LUA_TNIL: - t = "(Nil)"; - break; - case LUA_TNUMBER: - t.set("(Number) %f", lua_tonumber(L, i)); - break; - case LUA_TBOOLEAN: - t = String("(Bool) ") + (lua_toboolean(L, i) ? "true" : "false"); - break; - case LUA_TSTRING: - t = String("(String) ") + lua_tostring(L, i); - break; - case LUA_TTABLE: - t = "(Table)"; - break; - case LUA_TFUNCTION: - t = "(Function)"; - break; - default: - t = "Unknown"; - } - - printm(M_ERROR, String(i) + ": " + t + "\n"); - } -} - -int Lua::getmetatable(int i) { - return lua_getmetatable(L, i); -} - -int Lua::setmetatable(int i) { - return lua_setmetatable(L, i); -} - -int Lua::sethook(lua_Hook func, int mask, int count) { - return lua_sethook(L, func, mask, count); -} - -void Lua::do_break() { - lua_break(L); -} - -void LuaObject::push(Lua * L) throw (GeneralException) { - if (pushed && wantdestruct) { - throw GeneralException("Error: object is owned by the LUA script and can not be pushed."); - } - L->newtable(); - pushmembers(L); - pushed = true; -} - -void LuaObject::pushme(Lua * L, void * o, bool obj) { - void ** u; - bool * b; - L->push("__obj"); - u = (void **) L->newuser(sizeof(o) + sizeof(bool)); - *u = o; - b = (bool *) (u + 1); - *b = obj; - L->settable(-3, true); -} - -void * LuaObject::getme(Lua * L, int i) { - void ** r = 0; - - if (L->istable(i)) { - L->push("__obj"); - L->gettable(i, true); - if (!(r = (void **) L->touserdata())) - L->error("Table is not an object."); - if (!*r) - L->error("Object already destroyed."); - L->pop(); - } else if (L->isnil(i)) { - r = 0; - } else { - L->error("Not an object (not even a table)."); - } - - return r ? *r : 0; -} - -void LuaObject::pushit(Lua * L, const String & s, lua_CFunction f) { - L->push(s); - L->push(f); - L->settable(-3, true); -} - -void LuaObject::pushmeta(Lua * L, const String & s, lua_CFunction f) { - if (!L->getmetatable()) { - L->newtable(); - } - L->push(s); - L->push(f); - L->settable(); - L->setmetatable(); -} - -int LuaStatics::collector(lua_State * _L) { - Lua * L = Lua::find(_L); - void ** u = (void **) L->touserdata(); - bool * obj = (bool *) (u + 1); -// printm(M_INFO, "From LUA: collecting object\n"); - if (*obj) { -// printm(M_INFO, "Is object at %p\n", *u); - Base * b = (Base *) *u; - delete b; - } else { -// printm(M_INFO, "Is struct at %p\n", *u); - free(*u); - } - *u = 0; - return 0; -} - -int LuaStatics::destructor(lua_State * _L) { - Lua * L = Lua::find(_L); - Base * b = (Base *) LuaObject::getme(L); - delete b; - L->push("__obj"); - L->gettable(-2, true); - void ** u = (void **) L->touserdata(); - bool * obj = (bool *) (u + 1); - if (*obj) { - Base * b = (Base *) *u; - delete b; - } else { - free(*u); - } - *u = 0; - L->pop(); - return 0; -} - -void LuaObject::pushdestruct(Lua * L) throw (GeneralException) { - if (pushed) { - throw GeneralException("Error: can't push destructor, object already pushed"); - } - push(L); - L->push("__obj"); - L->gettable(-2, true); - pushmeta(L, "__gc", LuaStatics::collector); - L->pop(); - pushit(L, "destroy", LuaStatics::destructor); - - wantdestruct = true; -} - -LuaException::LuaException(String fn) : GeneralException(fn) { } - -LuaException::LuaException() { } +/* + * Baltisot + * Copyright (C) 1999-2003 Nicolas "Pixel" Noble + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id: BLua.cc,v 1.21 2004-11-27 21:01:20 pixel Exp $ */ + +#include "BLua.h" +#include + +#ifndef BUFFERSIZE +#define BUFFERSIZE 2048 +#endif + + + +extern "C" { + void do_lua_lock(lua_State * _L) { + Lua * L; + try { + L = Lua::find(_L); + } catch (GeneralException e) { + return; + } + L->lock(); + } + + void do_lua_unlock(lua_State * _L) { + Lua * L; + try { + L = Lua::find(_L); + } catch (GeneralException e) { + return; + } + L->unlock(); + } +} + +class LuaStatics : public Base { + public: + static const char * getF(lua_State *, void *, size_t *); + static int putF(lua_State *, const void *, size_t, void *); + static int luapanic(lua_State *); + static int trueluapanic(lua_State *) throw(GeneralException); + static int collector(lua_State *); + static int destructor(lua_State *); + + static int andB(lua_State *); + static int orB(lua_State *); + static int xorB(lua_State *); + static int notB(lua_State *); + static int hex(lua_State *); + static int shl(lua_State *); + static int shr(lua_State *); +}; + +std::map Lua::lualist; + +int LuaStatics::luapanic(lua_State * L) { + return trueluapanic(L); +} + +int LuaStatics::trueluapanic(lua_State * L) throw (GeneralException) { + Lua::find(L)->showerror(); + throw LuaException("Error running Lua code, bailing out."); +} + +int LuaStatics::andB(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + Uint32 a, b; + + if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { + L->error("Incorrect arguments to function `andB'"); + } + + a = L->tonumber(1); + b = L->tonumber(2); + + L->push((lua_Number) (a & b)); + + return 1; +} + +int LuaStatics::orB(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + Uint32 a, b; + + if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { + L->error("Incorrect arguments to function `orB'"); + } + + a = L->tonumber(1); + b = L->tonumber(2); + + L->push((lua_Number) (a | b)); + + return 1; +} + +int LuaStatics::xorB(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + Uint32 a, b; + + if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { + L->error("Incorrect arguments to function `xorB'"); + } + + a = L->tonumber(1); + b = L->tonumber(2); + + L->push((lua_Number) (a ^ b)); + + return 1; +} + +int LuaStatics::notB(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + Uint32 x; + + if ((n != 1) && !L->isnumber()) { + L->error("Incorrect arguments to function `notB'"); + } + + x = L->tonumber(); + + L->push((lua_Number) (~x)); + + return 1; +} + +int LuaStatics::shl(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + Uint32 a, b; + + if ((n > 2) && !L->isnumber(1) && ((n == 2) && !L->isnumber(2))) { + L->error("Incorrect arguments to function `shl'"); + } + + a = L->tonumber(1); + if (n == 2) + b = L->tonumber(2); + else + b = 1; + + L->push((lua_Number) (a << b)); + + return 1; +} + +int LuaStatics::shr(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + Uint32 a, b; + + if ((n > 2) && !L->isnumber(1) && ((n == 2) && !L->isnumber(2))) { + L->error("Incorrect arguments to function `shr'"); + } + + a = L->tonumber(1); + if (n == 2) + b = L->tonumber(2); + else + b = 1; + + L->push((lua_Number) (a >> b)); + + return 1; +} + +int LuaStatics::hex(lua_State * _L) { + Lua * L = Lua::find(_L); + int n = L->gettop(); + int x; + String r; + + if (((n != 1) || (n != 2)) && !L->isnumber(1) && ((n == 2) && !L->isstring(2))) { + L->error("Incorrect arguments to function `hex'"); + } + + x = L->tonumber(1); + String fmt = n == 2 ? L->tostring() : "%02x"; + r.set(fmt.to_charp(), x); + + L->push(r); + + return 1; +} + +Lua::Lua() : L(lua_open()) { + lua_atpanic(L, LuaStatics::luapanic); + lualist[L] = this; + + declarefunc("andB", LuaStatics::andB); + declarefunc("orB", LuaStatics::orB); + declarefunc("xorB", LuaStatics::xorB); + declarefunc("notB", LuaStatics::notB); + declarefunc("shl", LuaStatics::shl); + declarefunc("shr", LuaStatics::shr); + declarefunc("hex", LuaStatics::hex); +} + +Lua::Lua(lua_State * _L) : L(_L) { + lua_atpanic(L, LuaStatics::luapanic); + lualist[L] = this; +} + +Lua::~Lua() { + lua_setgcthreshold(L, 0); + lua_close(L); +} + +Lua::Lua(const Lua & l) throw (GeneralException) { + throw GeneralException("Error: can't duplicate a Lua object."); +} + +void Lua::open_base() { + luaopen_base(L); + lua_pop(L, 1); +} + +void Lua::open_table() { + luaopen_table(L); + lua_pop(L, 1); +} + +void Lua::open_io() { + luaopen_io(L); + lua_pop(L, 1); +} + +void Lua::open_string() { + luaopen_string(L); + lua_pop(L, 1); +} + +void Lua::open_math() { + luaopen_math(L); + lua_pop(L, 1); +} + +void Lua::open_debug() { + luaopen_debug(L); + lua_pop(L, 1); +} + +void Lua::open_dir() { + luaopen_dir(L); + lua_pop(L, 1); +} + +void Lua::declarefunc(const String & name, lua_CFunction f, int i) { + lua_pushstring(L, name.to_charp()); + lua_pushcfunction(L, f); + lua_settable(L, i); +} + +void Lua::call(const String & f, int i, int nargs, int nresults) { + lua_pushstring(L, f.to_charp()); + lua_gettable(L, i); + lua_insert(L, -1 - nargs - nresults); + lua_call(L, nargs, nresults); +} + +void Lua::call(int nargs, int nresults) { + lua_call(L, nargs, nresults); +} + +void Lua::push() { + lua_pushnil(L); +} + +void Lua::push(lua_Number n) { + lua_pushnumber(L, n); +} + +void Lua::push(const String & s) { + lua_pushlstring(L, s.to_charp(), s.strlen()); +} + +void Lua::push(bool b) { + lua_pushboolean(L, b); +} + +void Lua::push(char * s, int size) { + if (size < 0) { + lua_pushstring(L, s); + } else { + lua_pushlstring(L, s, size); + } +} + +void Lua::push(void * p) { + lua_pushlightuserdata(L, p); +} + +void Lua::push(lua_CFunction f, int n) { + lua_pushcclosure(L, f, n); +} + +void Lua::pop(int n) { + lua_pop(L, n); +} + +void Lua::newtable() { + lua_newtable(L); +} + +void * Lua::newuser(size_t s) { + return lua_newuserdata(L, s); +} + +void Lua::settable(int i, bool raw) { + if (raw) { + lua_rawset(L, i); + } else { + lua_settable(L, i); + } +} + +void Lua::gettable(int i, bool raw) { + if (raw) { + lua_rawget(L, i); + } else { + lua_gettable(L, i); + } +} + +void Lua::setvar() { + lua_settable(L, LUA_GLOBALSINDEX); +} + +int Lua::gettop() { + return lua_gettop(L); +} + +void Lua::error(const String & msg) { + push(msg); + lua_error(L); +} + +int Lua::type(int i) { + return lua_type(L, i); +} + +bool Lua::isnil(int i) { + return lua_isnil(L, i); +} + +bool Lua::isboolean(int i) { + return lua_isboolean(L, i); +} + +bool Lua::isnumber(int i) { + return lua_isnumber(L, i); +} + +bool Lua::isstring(int i) { + return lua_isstring(L, i); +} + +bool Lua::istable(int i) { + return lua_istable(L, i); +} + +bool Lua::isfunction(int i) { + return lua_isfunction(L, i); +} + +bool Lua::iscfunction(int i) { + return lua_iscfunction(L, i); +} + +bool Lua::isuserdata(int i) { + return lua_isuserdata(L, i); +} + +bool Lua::islightuserdata(int i) { + return lua_islightuserdata(L, i); +} + +bool Lua::toboolean(int i) { + return lua_toboolean(L, i); +} + +lua_Number Lua::tonumber(int i) { + return lua_tonumber(L, i); +} + +String Lua::tostring(int i) { + if (isnil(i)) + return String(); + return String(lua_tostring(L, i)); +} + +lua_CFunction Lua::tocfunction(int i) { + return lua_tocfunction(L, i); +} + +void * Lua::touserdata(int i) { + return lua_touserdata(L, i); +} + +Lua * Lua::tothread(int i) { + return find(lua_tothread(L, i)); +} + +struct LoadF { + Handle * f; + char buff[BUFFERSIZE]; +}; + +const char * LuaStatics::getF(lua_State * L, void * ud, size_t * size) { + LoadF *lf = (LoadF *)ud; + (void)L; + + *size = lf->f->read(lf->buff, BUFFERSIZE); + return (*size > 0) ? lf->buff : NULL; +} + +struct DumpF { + Handle * f; +}; + +int LuaStatics::putF(lua_State * L, const void * p, size_t size, void * ud) { + DumpF *lf = (DumpF *)ud; + (void)L; + + return lf->f->write(p, size) == size; +} + +void Lua::load(Handle * h, bool docall) throw (GeneralException) { + LoadF lf; + int status; + + lf.f = h; + + status = lua_load(L, LuaStatics::getF, &lf, h->GetName().to_charp()); + + if (status) { + showerror(); + throw LuaException("Error loading lua chunk from Handle `" + h->GetName() + "'"); + } + + if (docall) + call(); +} + +extern "C" void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void * uD); + +void Lua::dump(Handle * h, bool strip) { + DumpF lf; + + lf.f = h; + + luacmain(L, strip, LuaStatics::putF, &lf); +} + +Lua * Lua::thread() { + return new Lua(lua_newthread(L)); +} + +int Lua::yield(int nargs) { + return lua_yield(L, nargs); +} + +int Lua::resume(int nresults) { + return lua_resume(L, nresults); +} + +Lua * Lua::find(lua_State * _L) throw (GeneralException) { + std::map::iterator i; + + if ((i = lualist.find(_L)) == lualist.end()) { + throw GeneralException("Unable to find the Lua object for this context"); + } + + return i->second; +} + +void Lua::showerror() { + int n = lua_gettop(L); + int i; + String t; + + printm(M_ERROR, "Lua object: Got an LUA error\n"); + printm(M_ERROR, "Inspecting LUA stack\n"); + + if (n == 0) { + printm(M_ERROR, "Stack empty\n"); + return; + } + + for (i = 1; i <= n; i++) { + switch(lua_type(L, i)) { + case LUA_TNONE: + t = "Invalid"; + break; + case LUA_TNIL: + t = "(Nil)"; + break; + case LUA_TNUMBER: + t.set("(Number) %f", lua_tonumber(L, i)); + break; + case LUA_TBOOLEAN: + t = String("(Bool) ") + (lua_toboolean(L, i) ? "true" : "false"); + break; + case LUA_TSTRING: + t = String("(String) ") + lua_tostring(L, i); + break; + case LUA_TTABLE: + t = "(Table)"; + break; + case LUA_TFUNCTION: + t = "(Function)"; + break; + default: + t = "Unknown"; + } + + printm(M_ERROR, String(i) + ": " + t + "\n"); + } +} + +int Lua::getmetatable(int i) { + return lua_getmetatable(L, i); +} + +int Lua::setmetatable(int i) { + return lua_setmetatable(L, i); +} + +int Lua::sethook(lua_Hook func, int mask, int count) { + return lua_sethook(L, func, mask, count); +} + +void Lua::do_break() { + lua_break(L); +} + +void LuaObject::push(Lua * L) throw (GeneralException) { + if (pushed && wantdestruct) { + throw GeneralException("Error: object is owned by the LUA script and can not be pushed."); + } + L->newtable(); + pushmembers(L); + pushed = true; +} + +void LuaObject::pushme(Lua * L, void * o, bool obj) { + void ** u; + bool * b; + L->push("__obj"); + u = (void **) L->newuser(sizeof(o) + sizeof(bool)); + *u = o; + b = (bool *) (u + 1); + *b = obj; + L->settable(-3, true); +} + +void * LuaObject::getme(Lua * L, int i) { + void ** r = 0; + + if (L->istable(i)) { + L->push("__obj"); + L->gettable(i, true); + if (!(r = (void **) L->touserdata())) + L->error("Table is not an object."); + if (!*r) + L->error("Object already destroyed."); + L->pop(); + } else if (L->isnil(i)) { + r = 0; + } else { + L->error("Not an object (not even a table)."); + } + + return r ? *r : 0; +} + +void LuaObject::pushit(Lua * L, const String & s, lua_CFunction f) { + L->push(s); + L->push(f); + L->settable(-3, true); +} + +void LuaObject::pushmeta(Lua * L, const String & s, lua_CFunction f) { + if (!L->getmetatable()) { + L->newtable(); + } + L->push(s); + L->push(f); + L->settable(); + L->setmetatable(); +} + +int LuaStatics::collector(lua_State * _L) { + Lua * L = Lua::find(_L); + void ** u = (void **) L->touserdata(); + bool * obj = (bool *) (u + 1); +// printm(M_INFO, "From LUA: collecting object\n"); + if (*obj) { +// printm(M_INFO, "Is object at %p\n", *u); + Base * b = (Base *) *u; + delete b; + } else { +// printm(M_INFO, "Is struct at %p\n", *u); + free(*u); + } + *u = 0; + return 0; +} + +int LuaStatics::destructor(lua_State * _L) { + Lua * L = Lua::find(_L); + Base * b = (Base *) LuaObject::getme(L); + delete b; + L->push("__obj"); + L->gettable(-2, true); + void ** u = (void **) L->touserdata(); + bool * obj = (bool *) (u + 1); + if (*obj) { + Base * b = (Base *) *u; + delete b; + } else { + free(*u); + } + *u = 0; + L->pop(); + return 0; +} + +void LuaObject::pushdestruct(Lua * L) throw (GeneralException) { + if (pushed) { + throw GeneralException("Error: can't push destructor, object already pushed"); + } + push(L); + L->push("__obj"); + L->gettable(-2, true); + pushmeta(L, "__gc", LuaStatics::collector); + L->pop(); + pushit(L, "destroy", LuaStatics::destructor); + + wantdestruct = true; +} + +LuaException::LuaException(String fn) : GeneralException(fn) { } + +LuaException::LuaException() { } diff --git a/lib/lua/include/lualib.h b/lib/lua/include/lualib.h index bec0b94..081d7c3 100644 --- a/lib/lua/include/lualib.h +++ b/lib/lua/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.3 2003-12-11 16:53:28 pixel Exp $ +** $Id: lualib.h,v 1.4 2004-11-27 21:01:20 pixel Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -38,6 +38,9 @@ LUALIB_API int luaopen_math (lua_State *L); #define LUA_DBLIBNAME "debug" LUALIB_API int luaopen_debug (lua_State *L); +#define LUA_DIRLIBNAME "dir" +LUALIB_API int luaopen_dir (lua_State *L); + LUALIB_API int luaopen_loadlib (lua_State *L); diff --git a/lib/lua/src/LuaLib/ldirlib.c b/lib/lua/src/LuaLib/ldirlib.c new file mode 100644 index 0000000..b6760da --- /dev/null +++ b/lib/lua/src/LuaLib/ldirlib.c @@ -0,0 +1,101 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#define ldirlib_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +/* forward declaration for the iterator function */ +static int dir_iter (lua_State *L); + +static int l_dir (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + + /* create a userdatum to store a DIR address */ + DIR **d = (DIR **)lua_newuserdata(L, sizeof(DIR *)); + + /* set its metatable */ + luaL_getmetatable(L, "LuaBook.dir"); + lua_setmetatable(L, -2); + + /* try to open the given directory */ + *d = opendir(path); + if (*d == NULL) /* error opening the directory? */ + luaL_error(L, "cannot open %s: %s", path, + strerror(errno)); + + /* creates and returns the iterator function + (its sole upvalue, the directory userdatum, + is already on the stack top */ + lua_pushcclosure(L, dir_iter, 1); + return 1; +} + +static int dir_iter (lua_State *L) { + DIR *d = *(DIR **)lua_touserdata(L, lua_upvalueindex(1)); + struct dirent *entry; +#ifdef _WIN32 + struct _stat file_stat; +#else + struct stat file_stat; +#endif + if ((entry = readdir(d)) != NULL) { + lua_newtable(L); + lua_pushstring(L, "name"); + lua_pushstring(L, entry->d_name); + lua_settable(L, -3); +#ifdef _WIN32 + _stat(entry->d_name, &file_stat); +#else + stat(entry->d_name, &file_stat); +#endif + lua_pushstring(L, "type"); + lua_pushnumber(L, (S_IFREG & file_stat.st_mode) ? 2 : ((S_IFDIR & file_stat.st_mode) ? 1 : 0)); + lua_settable(L, -3); + + return 1; + } + else return 0; /* no more values to return */ +} + +static int dir_gc (lua_State *L) { + DIR *d = *(DIR **)lua_touserdata(L, 1); + if (d) closedir(d); + return 0; +} + +static const luaL_reg dirlib[] = { + {NULL, NULL} +}; + +int luaopen_dir (lua_State *L) { + luaL_openlib(L, LUA_DIRLIBNAME, dirlib, 0); + luaL_newmetatable(L, "LuaBook.dir"); + + /* set its __gc field */ + lua_pushstring(L, "__gc"); + lua_pushcfunction(L, dir_gc); + lua_settable(L, -3); + + /* register the `dir' function */ + lua_pushcfunction(L, l_dir); + lua_setglobal(L, "dir"); + + lua_pushnumber(L, 1); + lua_setglobal(L, "FLAG_DIR"); + + lua_pushnumber(L, 2); + lua_setglobal(L, "FLAG_FILE"); + + return 0; +} -- cgit v1.2.3