├── ltypelib.c ├── .gitignore ├── Makefile ├── LICENSE ├── lextlib.h ├── lextlib_lua52.h ├── ltypelib.h ├── macromagic.h ├── lextlib.c └── lextlib_global.h /ltypelib.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(LUA_VERSION),) 2 | LUA_VERSION=5.2 3 | endif 4 | 5 | ifeq ($(LUA_CPPFLAGS),) 6 | LUA_CPPFLAGS=-I/usr/include/lua$(LUA_VERSION) 7 | endif 8 | 9 | ifeq ($(LUA_LIBS),) 10 | LUA_LIBS=-llua$(LUA_VERSION) 11 | endif 12 | 13 | ifneq ($(DEBUG),) 14 | EXTRA_CFLAGS+= -g -O0 15 | endif 16 | 17 | CFLAGS=-Wall -Werror -pedantic -std=c99 -fPIC $(EXTRA_CFLAGS) 18 | CPPFLAGS=$(LUA_CPPFLAGS) 19 | LDFLAGS=-Wl,--no-undefined $(LUA_LDFLAGS) 20 | LIBS=$(LUA_LIBS) 21 | 22 | .PHONY: all 23 | all: liblextlib.so 24 | 25 | liblextlib.so: lextlib.o 26 | $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ $(LIBS) 27 | 28 | lextlib.o: lextlib.c lextlib.h lextlib_global.h lextlib_lua52.h 29 | 30 | .PHONY: clean 31 | clean: 32 | $(RM) *.so *.o 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Dennis Schridde 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /lextlib.h: -------------------------------------------------------------------------------- 1 | #ifndef LEXTLIB_H 2 | #define LEXTLIB_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "lextlib_global.h" 11 | #include "lextlib_lua52.h" 12 | 13 | 14 | #define LUAX_FUNCTION(prefix, function) { #function, prefix##function } 15 | 16 | /* [-0,+0,e] */ 17 | #define luaX_setconst(L, idx, prefix, val) \ 18 | (lua_pushinteger((L), (prefix##val)), lua_setfield((L), (idx) > 0 ? (idx) : (idx)-1, #val)) 19 | 20 | #define luaX_opt(L, func, narg, argname, def) \ 21 | (lua_isnoneornil((L), (narg)) ? (def) : func((L), (narg), (argname))) 22 | 23 | #define luaX_stkdbg(L) { \ 24 | int i, top = lua_gettop(L); \ 25 | fprintf(stderr, "L%d -> %d items\n", __LINE__, top); \ 26 | for (i = top; i > 0; i--) { \ 27 | printf(" [%d] %s = %s\n", i, lua_typename(L, lua_type(L, i)), (lua_isstring(L, i) ? lua_tostring(L, i) : "?")); \ 28 | } \ 29 | } 30 | 31 | #define luaX_passerr(L, func) { \ 32 | int ret = (func)(L); \ 33 | if (lua_isnil((L), -ret)) { \ 34 | return ret; \ 35 | } \ 36 | else { \ 37 | lua_pop((L), ret); \ 38 | } \ 39 | } 40 | 41 | 42 | #define LUAX_STR_TYPENAME "luax_typename" 43 | #define LUAX_STR_CLASS "luax_class" 44 | 45 | 46 | extern const char* luaX_status2str (int status); 47 | 48 | extern bool luaX_havetraceback (lua_State *L); 49 | extern int luaX_settraceback (lua_State *L); 50 | extern int luaX_traceback (lua_State *L); 51 | extern int luaX_panic (lua_State *L); 52 | 53 | extern void luaX_showstack (lua_State *L); 54 | extern void luaX_error (lua_State *L, const char *fmt, ...) LUAX_DECL_NORETURN; 55 | 56 | extern void luaX_preload (lua_State *L, const char *name, lua_CFunction function); 57 | extern void luaX_restrict (lua_State *L); 58 | 59 | extern const char* luaX_typename(lua_State *L, int narg); 60 | 61 | extern const char* luaX_pushargerror (lua_State *L, int narg, const char *argname, const char *extramsg); 62 | extern const char* luaX_pushtypeerror (lua_State *L, int narg, const char *argname, const char *tname); 63 | 64 | extern void luaX_checktype (lua_State *L, int narg, const char *argname, int t); 65 | extern int luaX_argerror (lua_State *L, int narg, const char *argname, const char *extramsg); 66 | extern int luaX_typeerror (lua_State *L, int narg, const char *argname, const char *tname); 67 | 68 | extern lua_Number luaX_checknumber (lua_State *L, int narg, const char *argname); 69 | extern lua_Number luaX_optnumber (lua_State *L, int narg, const char *argname, lua_Number def); 70 | 71 | extern lua_Integer luaX_checkinteger (lua_State *L, int narg, const char *argname); 72 | extern lua_Integer luaX_optinteger (lua_State *L, int narg, const char *argname, lua_Integer def); 73 | 74 | extern const char* luaX_checklstring (lua_State *L, int narg, const char *argname, size_t *len); 75 | extern const char* luaX_optlstring (lua_State *L, int narg, const char *argname, size_t *len, const char *def); 76 | 77 | extern void* luaX_checkudata (lua_State *L, int narg, const char *tname, const char *argname); 78 | extern void* luaX_optudata (lua_State *L, int narg, const char *tname, const char *argname, void *def); 79 | 80 | extern bool luaX_isclass (lua_State *L, int narg, const char *cname); 81 | extern void* luaX_testclass (lua_State *L, int narg, const char *cname); 82 | extern void* luaX_checkclass (lua_State *L, int narg, const char *cname, const char *argname); 83 | extern void* luaX_optclass (lua_State *L, int narg, const char *cname, const char *argname, void *def); 84 | 85 | 86 | static inline const char* luaX_checkstring (lua_State *L, int narg, const char *argname) { 87 | return luaX_checklstring(L, narg, argname, NULL); 88 | } 89 | 90 | 91 | static inline const char* luaX_optstring (lua_State *L, int narg, const char *argname, const char *def) { 92 | return luaX_optlstring(L, narg, argname, NULL, def); 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /lextlib_lua52.h: -------------------------------------------------------------------------------- 1 | #ifndef LEXTLIB_LUA52_H 2 | #define LEXTLIB_LUA52_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | #if LUA_VERSION_NUM < 502 12 | /* Error codes for lua_load: */ 13 | # define LUA_OK 0 14 | /* WARNING: This error does not exist in Lua 5.1 */ 15 | # define LUA_ERRGCMM (-1) 16 | 17 | /* Comparison types for lua_compare: */ 18 | # define LUA_OPEQ 0 19 | # define LUA_OPLT 1 20 | # define LUA_OPLE 2 21 | 22 | /* WARNING: Not entirely correct, but should work anyway */ 23 | # define lua_rawlen lua_objlen 24 | 25 | # define lua_absindex(L, i) (((i) > 0 || (i) < LUA_REGISTRYINDEX) ? (i) : lua_gettop(L)+(i)+1) 26 | 27 | /* WARNING: Something very different, but it might get your job done */ 28 | # define lua_getuservalue lua_getfenv 29 | # define lua_setuservalue lua_setfenv 30 | 31 | /* WARNING: Probably slower than Lua 5.2's implementation */ 32 | # define lua_compare luaX52_lua_compare 33 | 34 | # define lua_tonumberx(L,i,b) (lua_isnumber(L,(i)) ? (*(b)=1, lua_tonumber(L,(i))) : (*(b)=0, 0)) 35 | # define lua_tointegerx(L,i,b) (lua_isnumber(L,(i)) ? (*(b)=1, lua_tointeger(L,(i))) : (*(b)=0, 0)) 36 | 37 | # define luaL_getsubtable luaX52_luaL_getsubtable 38 | 39 | # define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) 40 | 41 | # define luaL_newlibtable(L,l) (lua_createtable(L,0,sizeof(l))) 42 | 43 | # define luaL_requiref(L,l,f,g) luaX52_luaL_requiref(L,(l),(f),(g)) 44 | 45 | # define luaL_setfuncs luaX52_luaL_setfuncs 46 | 47 | # define luaL_setmetatable(L,t) (luaL_getmetatable(L,t), lua_setmetatable(L,-2)) 48 | 49 | # define luaL_testudata(L,i,t) luaX52_luaL_testudata(L,(i),(t)) 50 | 51 | static inline void luaX52_luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { 52 | luaL_checkstack(L, nup, "too many upvalues"); 53 | for (; l->name != NULL; l++) { /* fill the table with given functions */ 54 | for (int i = 0; i < nup; i++) /* copy upvalues to the top */ 55 | lua_pushvalue(L, -nup); 56 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ 57 | lua_setfield(L, -(nup + 2), l->name); 58 | } 59 | lua_pop(L, nup); /* remove upvalues */ 60 | } 61 | 62 | static inline int luaX52_lua_compare(lua_State *L, int index1, int index2, int op) { 63 | assert(op == LUA_OPEQ || op == LUA_OPLT || op == LUA_OPLE); 64 | switch (op) { 65 | case LUA_OPEQ: 66 | return lua_equal(L, index1, index2); 67 | case LUA_OPLT: 68 | return lua_lessthan(L, index1, index2); 69 | case LUA_OPLE: 70 | return lua_lessthan(L, index1, index2) || lua_equal(L, index1, index2); 71 | default: 72 | return luaL_error(L, "Call to lua_compare with unsupported operator %d", op); 73 | } 74 | } 75 | 76 | static inline int luaX52_luaL_getsubtable(lua_State *L, int idx, const char *fname) { 77 | lua_getfield(L, idx, fname); 78 | if (lua_istable(L, -1)) return 1; /* table already there */ 79 | else { 80 | lua_pop(L, 1); /* remove previous result */ 81 | idx = lua_absindex(L, idx); 82 | lua_newtable(L); 83 | lua_pushvalue(L, -1); /* copy to be left at top */ 84 | lua_setfield(L, idx, fname); /* assign new table to field */ 85 | return 0; /* false, because did not find table there */ 86 | } 87 | } 88 | 89 | static inline void luaX52_luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) { 90 | lua_pushcfunction(L, openf); 91 | lua_pushstring(L, modname); /* argument to open function */ 92 | lua_call(L, 1, 1); /* open module */ 93 | luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); 94 | lua_pushvalue(L, -2); /* make copy of module (call result) */ 95 | lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ 96 | lua_pop(L, 1); /* remove _LOADED table */ 97 | if (glb) { 98 | lua_pushvalue(L, -1); /* copy of 'mod' */ 99 | lua_setglobal(L, modname); /* _G[modname] = module */ 100 | } 101 | } 102 | 103 | static inline void *luaX52_luaL_testudata(lua_State *L, int ud, const char *tname) { 104 | void *p = lua_touserdata(L, ud); 105 | if (p != NULL) { /* value is a userdata? */ 106 | if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ 107 | luaL_getmetatable(L, tname); /* get correct metatable */ 108 | if (!lua_rawequal(L, -1, -2)) /* not the same? */ 109 | p = NULL; /* value is a userdata with wrong metatable */ 110 | lua_pop(L, 2); /* remove both metatables */ 111 | return p; 112 | } 113 | } 114 | return NULL; /* value is not a userdata with a metatable */ 115 | } 116 | 117 | #endif 118 | 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /ltypelib.h: -------------------------------------------------------------------------------- 1 | struct s { 2 | int x, y; 3 | }; 4 | 5 | void meth(struct *s, int x, int y); 6 | int cmeth(lua_State *L) { 7 | struct s *_s; 8 | luaXt_pull(L, 1, s, &_s); // safe, since typechecks were done by wrapper 9 | int x = lua_tointeger(L, 2); 10 | int y = lua_tointeger(L, 3); 11 | meth(_s, x, y); 12 | return 0; 13 | } 14 | 15 | luaXt_declfield(s, x, int); 16 | luaXt_declfield(s, y, int); 17 | 18 | luaXt_declmethod(s, void, meth, 2, int, x, int, y); // FIXME What is this supposed to produce? 19 | luaXt_declcmethod(s, cmeth, 2, int, x, int, y); 20 | 21 | struct s *_s; 22 | luaXt_push(L, s, _s); 23 | 24 | // --- 25 | 26 | void fun(int x); 27 | int cfun(lua_State *L) { 28 | int x = lua_tointeger(L, 1); // safe, since typechecks were done by wrapper 29 | fun(x); 30 | return 0; 31 | } 32 | 33 | luaXt_declfunction(void, fun, 1, int, x); 34 | luaXt_declcfunction(cfun, 1, int, x); 35 | 36 | luaXt_pushcfunction(L, cfun); 37 | lua_setglobal(L, "fun"); 38 | 39 | // --- 40 | 41 | typedef struct luaXt_Type luaXt_Type; 42 | typedef struct luaXt_Field luaXt_Field; 43 | typedef struct luaXt_CMethod luaXt_CMethod; 44 | typedef struct luaXt_Argument luaXt_Argument; 45 | typedef struct luaXt_CFunction luaXt_CFunction; 46 | 47 | struct luaXt_Type { 48 | const char *name; 49 | bool (*is)(lua_State*, int narg); // FIXME call it "test" instead? 50 | void (*push)(lua_State*, void*); 51 | void (*pull)(lua_State*, int narg, void*); 52 | int type; // LUA_TTABLE, LUA_TLIGHTUSERDATA or LUA_TUSERDATA 53 | union { 54 | struct { 55 | int nfields; 56 | luaXt_Field fields[]; 57 | } table; 58 | struct { 59 | int nmethods; 60 | luaXt_CMethod methods[]; 61 | } udata; 62 | }; 63 | }; 64 | 65 | struct luaXt_Field { 66 | const char *name; 67 | luaXt_Type *type; 68 | }; 69 | 70 | struct luaXt_CMethod { 71 | luaXt_Type *self; 72 | const char *name; 73 | lua_CFunction function; 74 | }; 75 | 76 | #ifdef 0 77 | struct luaXt_CMethod { 78 | luaXt_Type *self; 79 | luaXt_CFunction f; 80 | }; 81 | 82 | #include "macromagic.h" 83 | 84 | #define luaXt_declcfunction(function, ...) \ 85 | luaXt_declcfunction_impl(function, STRINGIFY function, NUM_ARGS(__VA_ARGS__)/2, FOREACH(STRINGIFY, (__VA_ARGS__))) 86 | 87 | #define luaXt_pushcfunction(L, function) \ 88 | luaXt_pushcfunction_impl(L, STRINGIFY function) 89 | 90 | struct luaXt_Argument { 91 | const char *name; 92 | luaXt_Type *type; 93 | }; 94 | 95 | struct luaXt_CFunction { 96 | const char *name; 97 | lua_CFunction function; 98 | int nargs; 99 | luaXt_Argument args[]; 100 | }; 101 | 102 | 103 | void luaXt_declcfunction_impl(lua_CFunction function, const char *fname, int nargs, ...) { 104 | va_list ap; 105 | 106 | luaXt_CFunction *f = malloc(sizeof(luaXt_CFunction) + nargs*sizeof(luaXt_Argument)); 107 | *f = (luaXt_CFunction){ 108 | function, 109 | strdup(fname), 110 | nargs 111 | }; 112 | 113 | va_start(ap, nargs); 114 | 115 | for (int i = 0; i < nargs; i++) { 116 | const char *arg_tname = va_arg(ap, const char*); 117 | const char *arg_name = va_arg(ap, const char*); 118 | 119 | luaXt_Type *targ = find_type(arg_tname); 120 | if (targ == NULL) { 121 | bail(); 122 | } 123 | 124 | f->args[i] = (luaXt_Argument){strdup(arg_name), targ}; 125 | } 126 | 127 | va_end(ap); 128 | 129 | insert_cfunction(f); // map[fname] = f 130 | } 131 | 132 | void luaXt_pushcfunction_impl(lua_State *L, const char *fname) { 133 | luaXt_CFunction *f = find_cfunction(fname); // f = map[fname] 134 | 135 | lua_pushlightuserdata(L, f); 136 | lua_pushcclosure(L, wrap_cfunction, 1); 137 | } 138 | 139 | int wrap_cfunction(lua_State *L) { 140 | luaXt_CFunction *f = lua_touserdata(L, lua_upvalueindex(1)); 141 | 142 | for (int i = 0; i < f->nargs; i++) { 143 | luaXt_Argument *arg = &f->args[i]; 144 | 145 | if (!arg->type->is(L, i)) { 146 | return typeerror(L, i, f, arg); 147 | } 148 | } 149 | 150 | return f->function(L); 151 | } 152 | 153 | int wrap_cmethod(lua_State *L) { 154 | luaXt_CMethod *m = lua_touserdata(L, lua_upvalueindex(1)); 155 | 156 | void *self = luaX_testclass(L, 1, m->self->name, "self"); // FIXME Why not use checkclass instead? 157 | if (self == NULL) { 158 | return typeerror(L, 0, &m->f, m->self); // FIXME what is this exactly? 159 | } 160 | 161 | for (int i = 0; i < m->f.nargs; i++) { 162 | luaXt_Argument *arg = &m->f.args[i]; 163 | 164 | if (!arg->type->is(L, i+1)) { // FIXME Why not use check functions instead? 165 | return typeerror(L, i, &m->f, arg); 166 | } 167 | } 168 | 169 | return m->f.function(L); 170 | } 171 | 172 | // -- 173 | 174 | Creating a function that will call through to Lua: 175 | 176 | luaXt_declfunction(void, fun, 1, int, x); 177 | 178 | #define luaXt_declfunction(rtype, function, ...) \ 179 | luaXt_declfunction_impl(STRINGIFY rtype, function, STRINGIFY function, NUM_ARGS(__VA_ARGS__), FOREACH(STRINGIFY, (__VA_ARGS__))) 180 | 181 | // FIXME: Idea using the macro technique: 182 | FOREACH_PAIR(PUSHARG, (__VA_ARGS__)); 183 | 184 | #define PUSHARG(arg_tname, arg_name) PUSHARG_##arg_tname(arg_name) 185 | #define PUSHARG_int(arg_name) lua_pushinteger(L, arg_name) 186 | 187 | 188 | void luaXt_declfunction_impl(const char *rtype, lua_CFunction function, const char *fname, int nargs, ...) { 189 | 190 | } 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /macromagic.h: -------------------------------------------------------------------------------- 1 | #ifndef MACROMAGIC_H 2 | 3 | #define _NUM_ARGS(X100, X99, X98, X97, X96, X95, X94, X93, X92, X91, X90, X89, X88, X87, X86, X85, X84, X83, X82, X81, X80, X79, X78, X77, X76, X75, X74, X73, X72, X71, X70, X69, X68, X67, X66, X65, X64, X63, X62, X61, X60, X59, X58, X57, X56, X55, X54, X53, X52, X51, X50, X49, X48, X47, X46, X45, X44, X43, X42, X41, X40, X39, X38, X37, X36, X35, X34, X33, X32, X31, X30, X29, X28, X27, X26, X25, X24, X23, X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, N, ...) N 4 | 5 | #define NUM_ARGS(...) _NUM_ARGS(__VA_ARGS__, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 6 | 7 | #define STRINGIFY(X) #X 8 | 9 | #define EXPAND(X) X 10 | #define FIRSTARG(X, ...) (X) 11 | #define RESTARGS(X, ...) (__VA_ARGS__) 12 | 13 | #define FOREACH(MACRO, LIST) FOREACH_(NUM_ARGS LIST, MACRO, LIST) 14 | #define FOREACH_(N, M, LIST) FOREACH__(N, M, LIST) 15 | #define FOREACH__(N, M, LIST) FOREACH_##N(M, LIST) 16 | #define FOREACH_1(M, LIST) M LIST 17 | #define FOREACH_2(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_1(M, RESTARGS LIST) 18 | #define FOREACH_3(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_2(M, RESTARGS LIST) 19 | #define FOREACH_4(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_3(M, RESTARGS LIST) 20 | #define FOREACH_5(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_4(M, RESTARGS LIST) 21 | #define FOREACH_6(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_5(M, RESTARGS LIST) 22 | #define FOREACH_7(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_6(M, RESTARGS LIST) 23 | #define FOREACH_8(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_7(M, RESTARGS LIST) 24 | #define FOREACH_9(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_8(M, RESTARGS LIST) 25 | #define FOREACH_10(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_9(M, RESTARGS LIST) 26 | #define FOREACH_11(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_10(M, RESTARGS LIST) 27 | #define FOREACH_12(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_11(M, RESTARGS LIST) 28 | #define FOREACH_13(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_12(M, RESTARGS LIST) 29 | #define FOREACH_14(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_13(M, RESTARGS LIST) 30 | #define FOREACH_15(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_14(M, RESTARGS LIST) 31 | #define FOREACH_16(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_15(M, RESTARGS LIST) 32 | #define FOREACH_17(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_16(M, RESTARGS LIST) 33 | #define FOREACH_18(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_17(M, RESTARGS LIST) 34 | #define FOREACH_19(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_18(M, RESTARGS LIST) 35 | #define FOREACH_20(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_19(M, RESTARGS LIST) 36 | #define FOREACH_21(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_20(M, RESTARGS LIST) 37 | #define FOREACH_22(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_21(M, RESTARGS LIST) 38 | #define FOREACH_23(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_22(M, RESTARGS LIST) 39 | #define FOREACH_24(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_23(M, RESTARGS LIST) 40 | #define FOREACH_25(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_24(M, RESTARGS LIST) 41 | #define FOREACH_26(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_25(M, RESTARGS LIST) 42 | #define FOREACH_27(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_26(M, RESTARGS LIST) 43 | #define FOREACH_28(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_27(M, RESTARGS LIST) 44 | #define FOREACH_29(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_28(M, RESTARGS LIST) 45 | #define FOREACH_30(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_29(M, RESTARGS LIST) 46 | #define FOREACH_31(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_30(M, RESTARGS LIST) 47 | #define FOREACH_32(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_31(M, RESTARGS LIST) 48 | #define FOREACH_33(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_32(M, RESTARGS LIST) 49 | #define FOREACH_34(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_33(M, RESTARGS LIST) 50 | #define FOREACH_35(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_34(M, RESTARGS LIST) 51 | #define FOREACH_36(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_35(M, RESTARGS LIST) 52 | #define FOREACH_37(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_36(M, RESTARGS LIST) 53 | #define FOREACH_38(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_37(M, RESTARGS LIST) 54 | #define FOREACH_39(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_38(M, RESTARGS LIST) 55 | #define FOREACH_40(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_39(M, RESTARGS LIST) 56 | #define FOREACH_41(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_40(M, RESTARGS LIST) 57 | #define FOREACH_42(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_41(M, RESTARGS LIST) 58 | #define FOREACH_43(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_42(M, RESTARGS LIST) 59 | #define FOREACH_44(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_43(M, RESTARGS LIST) 60 | #define FOREACH_45(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_44(M, RESTARGS LIST) 61 | #define FOREACH_46(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_45(M, RESTARGS LIST) 62 | #define FOREACH_47(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_46(M, RESTARGS LIST) 63 | #define FOREACH_48(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_47(M, RESTARGS LIST) 64 | #define FOREACH_49(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_48(M, RESTARGS LIST) 65 | #define FOREACH_50(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_49(M, RESTARGS LIST) 66 | #define FOREACH_51(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_50(M, RESTARGS LIST) 67 | #define FOREACH_52(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_51(M, RESTARGS LIST) 68 | #define FOREACH_53(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_52(M, RESTARGS LIST) 69 | #define FOREACH_54(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_53(M, RESTARGS LIST) 70 | #define FOREACH_55(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_54(M, RESTARGS LIST) 71 | #define FOREACH_56(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_55(M, RESTARGS LIST) 72 | #define FOREACH_57(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_56(M, RESTARGS LIST) 73 | #define FOREACH_58(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_57(M, RESTARGS LIST) 74 | #define FOREACH_59(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_58(M, RESTARGS LIST) 75 | #define FOREACH_60(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_59(M, RESTARGS LIST) 76 | #define FOREACH_61(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_60(M, RESTARGS LIST) 77 | #define FOREACH_62(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_61(M, RESTARGS LIST) 78 | #define FOREACH_63(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_62(M, RESTARGS LIST) 79 | #define FOREACH_64(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_63(M, RESTARGS LIST) 80 | #define FOREACH_65(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_64(M, RESTARGS LIST) 81 | #define FOREACH_66(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_65(M, RESTARGS LIST) 82 | #define FOREACH_67(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_66(M, RESTARGS LIST) 83 | #define FOREACH_68(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_67(M, RESTARGS LIST) 84 | #define FOREACH_69(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_68(M, RESTARGS LIST) 85 | #define FOREACH_70(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_69(M, RESTARGS LIST) 86 | #define FOREACH_71(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_70(M, RESTARGS LIST) 87 | #define FOREACH_72(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_71(M, RESTARGS LIST) 88 | #define FOREACH_73(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_72(M, RESTARGS LIST) 89 | #define FOREACH_74(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_73(M, RESTARGS LIST) 90 | #define FOREACH_75(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_74(M, RESTARGS LIST) 91 | #define FOREACH_76(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_75(M, RESTARGS LIST) 92 | #define FOREACH_77(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_76(M, RESTARGS LIST) 93 | #define FOREACH_78(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_77(M, RESTARGS LIST) 94 | #define FOREACH_79(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_78(M, RESTARGS LIST) 95 | #define FOREACH_80(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_79(M, RESTARGS LIST) 96 | #define FOREACH_81(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_80(M, RESTARGS LIST) 97 | #define FOREACH_82(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_81(M, RESTARGS LIST) 98 | #define FOREACH_83(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_82(M, RESTARGS LIST) 99 | #define FOREACH_84(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_83(M, RESTARGS LIST) 100 | #define FOREACH_85(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_84(M, RESTARGS LIST) 101 | #define FOREACH_86(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_85(M, RESTARGS LIST) 102 | #define FOREACH_87(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_86(M, RESTARGS LIST) 103 | #define FOREACH_88(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_87(M, RESTARGS LIST) 104 | #define FOREACH_89(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_88(M, RESTARGS LIST) 105 | #define FOREACH_90(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_89(M, RESTARGS LIST) 106 | #define FOREACH_91(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_90(M, RESTARGS LIST) 107 | #define FOREACH_92(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_91(M, RESTARGS LIST) 108 | #define FOREACH_93(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_92(M, RESTARGS LIST) 109 | #define FOREACH_94(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_93(M, RESTARGS LIST) 110 | #define FOREACH_95(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_94(M, RESTARGS LIST) 111 | #define FOREACH_96(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_95(M, RESTARGS LIST) 112 | #define FOREACH_97(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_96(M, RESTARGS LIST) 113 | #define FOREACH_98(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_97(M, RESTARGS LIST) 114 | #define FOREACH_99(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_98(M, RESTARGS LIST) 115 | #define FOREACH_100(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_99(M, RESTARGS LIST) 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /lextlib.c: -------------------------------------------------------------------------------- 1 | #include "lextlib.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | 12 | static int luax_traceback_function = 0; 13 | 14 | 15 | bool luaX_havetraceback (lua_State *L) { 16 | lua_pushlightuserdata(L, &luax_traceback_function); // [-0,+1,-] 17 | lua_rawget(L, LUA_REGISTRYINDEX); // [-1,+1,-] 18 | bool result = lua_isfunction(L, -1); // [-0,+0,-] 19 | lua_pop(L, 1); // [-1,+0,-] 20 | return result; 21 | } 22 | 23 | 24 | int luaX_settraceback (lua_State *L) { 25 | luaX_checktype(L, 1, "traceback function", LUA_TFUNCTION); // [-0,+0,e] 26 | lua_pushlightuserdata(L, &luax_traceback_function); // [-0,+1,-] 27 | lua_pushvalue(L, 1); // [-0,+1,-] 28 | lua_rawset(L, LUA_REGISTRYINDEX); // [-1,+1,-] 29 | return 0; 30 | } 31 | 32 | 33 | int luaX_traceback (lua_State *L) { 34 | lua_pushlightuserdata(L, &luax_traceback_function); // [-0,+1,-] 35 | lua_rawget(L, LUA_REGISTRYINDEX); // [-1,+1,-] 36 | if (!lua_isfunction(L, -1)) { // [-0,+0,-] 37 | lua_pop(L, 1); // [-1,+0,-] 38 | return 1; 39 | } 40 | 41 | lua_insert(L, -2); /* shift function below error message */ // [-1,+1,-] 42 | lua_pushinteger(L, 2); /* skip this function in the trace */ // [-0,+1,-] 43 | lua_call(L, 2, 1); /* call traceback function */ // [-3,+1,e] 44 | 45 | return 1; 46 | } 47 | 48 | 49 | int luaX_panic (lua_State *L) { 50 | int nresults = luaX_traceback(L); 51 | if (nresults != 1) { 52 | fprintf(stderr, "Unable to get backtrace: Unexpected number of results (%d)\n", nresults); 53 | return 0; 54 | } 55 | 56 | if (!lua_isstring(L, -1)) { 57 | fprintf(stderr, "Unable to get backtrace: Result not a string\n"); 58 | return 0; 59 | } 60 | 61 | const char *err = lua_tostring(L, -1); 62 | if (err == NULL) { 63 | fprintf(stderr, "Unable to get backtrace: Cannot convert result to string\n"); 64 | return 0; 65 | } 66 | 67 | fprintf(stderr, "PANIC: %s\n", err); 68 | 69 | return 0; 70 | } 71 | 72 | 73 | void luaX_showstack (lua_State *L) { //> [-0,+0,e] 74 | lua_pushcfunction(L, luaX_traceback); /* push traceback function */ 75 | lua_pushnil(L); 76 | 77 | if (lua_pcall(L, 1, 1, 0) != LUA_OK) { 78 | fprintf(stderr, "Unable to get backtrace: Executing traceback function failed\n"); 79 | return; 80 | } 81 | 82 | if (!lua_isstring(L, -1)) { 83 | fprintf(stderr, "Unable to get backtrace: Result not a string\n"); 84 | return; 85 | } 86 | 87 | const char *err = lua_tostring(L, -1); 88 | if (err == NULL) { 89 | fprintf(stderr, "Unable to get backtrace: Cannot convert result to string\n"); 90 | return; 91 | } 92 | 93 | fprintf(stderr, "DEBUG: %s\n", err); 94 | 95 | lua_pop(L, 1); 96 | } 97 | 98 | 99 | void luaX_error (lua_State *L, const char *fmt, ...) { 100 | va_list argp; 101 | 102 | va_start(argp, fmt); 103 | vfprintf(stderr, fmt, argp); 104 | va_end(argp); 105 | 106 | lua_close(L); 107 | 108 | exit (EXIT_FAILURE); 109 | } 110 | 111 | 112 | void luaX_preload(lua_State *L, const char *name, lua_CFunction init_function) { 113 | lua_getglobal(L, "package"); // [-0,+1,e] 114 | lua_getfield(L, -1, "preload"); // [-0,+1,e] 115 | lua_pushcfunction(L, init_function); // [-0,+1,-] 116 | lua_setfield(L, -2, name); // package.preload[name] = init_function // [-1,+0,e] 117 | lua_pop(L, 2); // pop (package.preload, package) // [-2,+0,-] 118 | } 119 | 120 | 121 | void luaX_restrict(lua_State *L) { 122 | lua_getglobal(L, "package"); // [-0,+1,e] 123 | lua_getfield(L, -1, "searchers"); // [-0,+1,e] 124 | lua_newtable(L); // push ($newtable) // [-0,+1,e] 125 | lua_rawgeti(L, -2, 1); // push (package.searchers[1]) // [-0,+1,-] 126 | lua_rawseti(L, -2, 1); // $newtable[1] = top, pop // [-1,+0,e] 127 | lua_setfield(L, -3, "searchers"); // package.searchers = top, pop // [-1,+0,e] 128 | lua_pop(L, 2); // pop ($package.searchers, package) // [-2,+0,-] 129 | } 130 | 131 | 132 | const char *luaX_typename(lua_State *L, int narg) { 133 | if (luaL_getmetafield(L, narg, LUAX_STR_TYPENAME)) { 134 | const char *cname = lua_tostring(L, -1); 135 | lua_pop(L, 1); // FIXME might free the string 136 | return cname; 137 | } 138 | 139 | if (luaL_getmetafield(L, narg, LUAX_STR_CLASS)) { 140 | if (luaL_getmetafield(L, -1, LUAX_STR_TYPENAME)) { 141 | const char *cname = lua_tostring(L, -1); 142 | lua_pop(L, 2); // FIXME might free the string 143 | return cname; 144 | } 145 | 146 | lua_pop(L, 1); 147 | } 148 | 149 | return luaL_typename(L, narg); 150 | } 151 | 152 | 153 | const char* luaX_pushargerror (lua_State *L, int narg, const char *argname, const char *extramsg) { 154 | const char *msg = NULL; 155 | 156 | if (argname != NULL) { 157 | msg = lua_pushfstring(L, LUA_QS ": %s", argname, extramsg); 158 | } 159 | else { 160 | #if LUA_VERSION_NUM >= 502 161 | msg = lua_pushstring(L, extramsg); 162 | #else 163 | msg = lua_pushfstring(L, "%s", extramsg); 164 | #endif 165 | } 166 | 167 | return msg; 168 | } 169 | 170 | 171 | int luaX_argerror (lua_State *L, int narg, const char *argname, const char *extramsg) { 172 | const char *msg = luaX_pushargerror(L, narg, argname, extramsg); 173 | 174 | return luaL_argerror(L, narg, msg); 175 | } 176 | 177 | 178 | const char* luaX_pushtypeerror (lua_State *L, int narg, const char *argname, const char *tname) { 179 | return lua_pushfstring(L, "%s expected, got %s", tname, luaX_typename(L, narg)); 180 | } 181 | 182 | int luaX_typeerror (lua_State *L, int narg, const char *argname, const char *tname) { 183 | const char *msg = luaX_pushtypeerror(L, narg, argname, tname); 184 | 185 | return luaX_argerror(L, narg, argname, msg); 186 | } 187 | 188 | 189 | static int tag_error (lua_State *L, int narg, const char *argname, int tag) { 190 | return luaX_typeerror(L, narg, argname, lua_typename(L, tag)); 191 | } 192 | 193 | 194 | void luaX_checktype (lua_State *L, int narg, const char *argname, int t) { 195 | if (lua_type(L, narg) != t) 196 | tag_error(L, narg, argname, t); 197 | } 198 | 199 | 200 | lua_Number luaX_checknumber (lua_State *L, int narg, const char *argname) { 201 | int isnum = false; 202 | lua_Number d = lua_tonumberx(L, narg, &isnum); 203 | 204 | if (!isnum) { 205 | tag_error(L, narg, argname, LUA_TNUMBER); 206 | } 207 | 208 | return d; 209 | } 210 | 211 | 212 | lua_Number luaX_optnumber (lua_State *L, int narg, const char *argname, lua_Number def) { 213 | return luaX_opt(L, luaX_checknumber, narg, argname, def); 214 | } 215 | 216 | 217 | lua_Integer luaX_checkinteger (lua_State *L, int narg, const char *argname) { 218 | int isnum = false; 219 | lua_Integer d = lua_tointegerx(L, narg, &isnum); 220 | 221 | if (!isnum) { 222 | tag_error(L, narg, argname, LUA_TNUMBER); 223 | } 224 | 225 | return d; 226 | } 227 | 228 | 229 | lua_Integer luaX_optinteger (lua_State *L, int narg, const char *argname, lua_Integer def) { 230 | return luaX_opt(L, luaX_checkinteger, narg, argname, def); 231 | } 232 | 233 | 234 | const char* luaX_checklstring (lua_State *L, int narg, const char *argname, size_t *len) { 235 | const char *s = lua_tolstring(L, narg, len); 236 | 237 | if (s == NULL) { 238 | tag_error(L, narg, argname, LUA_TSTRING); 239 | } 240 | 241 | return s; 242 | } 243 | 244 | 245 | const char* luaX_optlstring (lua_State *L, int narg, const char *argname, size_t *len, const char *def) { 246 | if (lua_isnoneornil(L, narg)) { 247 | if (len != NULL) { 248 | *len = def ? strlen(def) : 0; 249 | } 250 | 251 | return def; 252 | } 253 | 254 | return luaX_checklstring(L, narg, argname, len); 255 | } 256 | 257 | 258 | void* luaX_checkudata (lua_State *L, int narg, const char *argname, const char *tname) { 259 | void *d = luaL_testudata(L, narg, tname); 260 | 261 | if (d == NULL) { 262 | luaX_typeerror(L, narg, argname, tname); 263 | } 264 | 265 | return d; 266 | } 267 | 268 | 269 | void* luaX_optudata (lua_State *L, int narg, const char *argname, const char *tname, void* def) { 270 | if (lua_isnoneornil(L, narg)) { 271 | return def; 272 | } 273 | 274 | return luaX_checkudata(L, narg, argname, tname); 275 | } 276 | 277 | 278 | bool luaX_isclass (lua_State *L, int narg, const char *cname) { 279 | narg = lua_absindex(L, narg); 280 | 281 | lua_getmetatable(L, narg); 282 | luaL_getmetatable(L, cname); 283 | 284 | if (lua_rawequal(L, -1, -2)) { 285 | lua_pop(L, 2); 286 | return true; 287 | } 288 | 289 | if (!luaL_getmetafield(L, narg, LUAX_STR_CLASS)) { 290 | lua_pop(L, 2); 291 | return false; 292 | } 293 | 294 | if (lua_rawequal(L, -1, -2)) { 295 | lua_pop(L, 3); 296 | return true; 297 | } 298 | 299 | lua_pop(L, 3); 300 | 301 | return false; 302 | } 303 | 304 | 305 | void* luaX_testclass (lua_State *L, int narg, const char *cname) { 306 | void *p = lua_touserdata(L, narg); 307 | if (p == NULL) { 308 | return NULL; 309 | } 310 | 311 | if (luaX_isclass(L, narg, cname)) { 312 | return p; 313 | } 314 | 315 | return NULL; 316 | } 317 | 318 | void* luaX_checkclass (lua_State *L, int narg, const char *cname, const char *argname) { 319 | void *p = luaX_testclass(L, narg, cname); 320 | if (p == NULL) { 321 | luaX_typeerror(L, narg, argname, cname); 322 | } 323 | 324 | return p; 325 | } 326 | 327 | 328 | const char* luaX_status2str (int status) { 329 | switch (status) { 330 | case LUA_OK: 331 | return "no error"; 332 | case LUA_YIELD: 333 | return "yield"; 334 | case LUA_ERRRUN: 335 | return "runtime error"; 336 | case LUA_ERRSYNTAX: 337 | return "syntax error"; 338 | case LUA_ERRMEM: 339 | return "memory allocation error"; 340 | case LUA_ERRGCMM: 341 | return "garbage collector error"; 342 | case LUA_ERRERR: 343 | return "message handler error"; 344 | default: 345 | return "unknown error"; 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /lextlib_global.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of lextlib. 3 | Copyright (C) 1992-2007 Trolltech ASA. 4 | Copyright (C) 2005-2009 Warzone Resurrection Project 5 | 6 | lextlib is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | lextlib is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with lextlib; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | /*! \file lextlib_global.h 22 | * \brief Platform detection, workarounds and compat fixes 23 | * 24 | * OS and CC detection code shamelessly stolen from Qt4 (Qt/qglobal.h) by Dennis. 25 | * This has been stripped down, feel free to add checks as you need them. 26 | */ 27 | 28 | #ifndef WZGLOBAL_H 29 | #define WZGLOBAL_H 30 | 31 | 32 | #if defined(HAVE_CONFIG_H) 33 | # include "config.h" 34 | #elif defined(__MACOSX__) 35 | # include "config-macosx.h" 36 | #endif 37 | 38 | 39 | /* ---- Platform detection ---- */ 40 | 41 | 42 | /* 43 | The operating system, must be one of: (LUAX_OS_x) 44 | 45 | DARWIN - Darwin OS (synonym for LUAX_OS_MAC) 46 | OS2 - OS/2 47 | OS2EMX - XFree86 on OS/2 (not PM) 48 | WIN32 - Win32 (Windows 95/98/ME and Windows NT/2000/XP) 49 | CYGWIN - Cygwin 50 | SOLARIS - Sun Solaris 51 | HPUX - HP-UX 52 | ULTRIX - DEC Ultrix 53 | LINUX - Linux 54 | FREEBSD - FreeBSD 55 | GNU_kFREEBSD - GNU/kFreeBSD 56 | NETBSD - NetBSD 57 | OPENBSD - OpenBSD 58 | BSDI - BSD/OS 59 | IRIX - SGI Irix 60 | OSF - HP Tru64 UNIX 61 | SCO - SCO OpenServer 5 62 | UNIXWARE - UnixWare 7, Open UNIX 8 63 | AIX - AIX 64 | HURD - GNU Hurd 65 | DGUX - DG/UX 66 | RELIANT - Reliant UNIX 67 | DYNIX - DYNIX/ptx 68 | QNX - QNX 69 | QNX6 - QNX RTP 6.1 70 | LYNX - LynxOS 71 | BSD4 - Any BSD 4.4 system 72 | UNIX - Any UNIX BSD/SYSV system 73 | */ 74 | 75 | #if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__)) 76 | # define LUAX_OS_DARWIN 77 | # define LUAX_OS_BSD4 78 | # ifdef __LP64__ 79 | # define LUAX_OS_DARWIN64 80 | # else 81 | # define LUAX_OS_DARWIN32 82 | # endif 83 | #elif defined(__CYGWIN__) 84 | # define LUAX_OS_CYGWIN 85 | #elif defined(__OS2__) 86 | # if defined(__EMX__) 87 | # define LUAX_OS_OS2EMX 88 | # else 89 | # define LUAX_OS_OS2 90 | # endif 91 | #elif !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) 92 | # define LUAX_OS_WIN32 93 | # define LUAX_OS_WIN64 94 | #elif !defined(SAG_COM) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) 95 | # define LUAX_OS_WIN32 96 | #elif defined(__MWERKS__) && defined(__INTEL__) 97 | # define LUAX_OS_WIN32 98 | #elif defined(__sun) || defined(sun) 99 | # define LUAX_OS_SOLARIS 100 | #elif defined(hpux) || defined(__hpux) 101 | # define LUAX_OS_HPUX 102 | #elif defined(__ultrix) || defined(ultrix) 103 | # define LUAX_OS_ULTRIX 104 | #elif defined(sinix) 105 | # define LUAX_OS_RELIANT 106 | #elif defined(__linux__) || defined(__linux) 107 | # define LUAX_OS_LINUX 108 | #elif defined(__FreeBSD__) || defined(__DragonFly__) 109 | # define LUAX_OS_FREEBSD 110 | # define LUAX_OS_BSD4 111 | #elif defined(__FreeBSD_kernel__) && !defined(__FreeBSD__) 112 | /* We're running a non-FreeBSD system with a FreeBSD kernel. Find out what C 113 | * library we're using to detect the system we're running on. */ 114 | # include 115 | # if defined(__GLIBC__) 116 | /* We're running GNU/kFreeBSD */ 117 | # define LUAX_OS_GNU_kFREEBSD 118 | # endif 119 | #elif defined(__NetBSD__) 120 | # define LUAX_OS_NETBSD 121 | # define LUAX_OS_BSD4 122 | #elif defined(__OpenBSD__) 123 | # define LUAX_OS_OPENBSD 124 | # define LUAX_OS_BSD4 125 | #elif defined(__bsdi__) 126 | # define LUAX_OS_BSDI 127 | # define LUAX_OS_BSD4 128 | #elif defined(__sgi) 129 | # define LUAX_OS_IRIX 130 | #elif defined(__osf__) 131 | # define LUAX_OS_OSF 132 | #elif defined(_AIX) 133 | # define LUAX_OS_AIX 134 | #elif defined(__Lynx__) 135 | # define LUAX_OS_LYNX 136 | #elif defined(__GNU__) 137 | # define LUAX_OS_HURD 138 | #elif defined(__DGUX__) 139 | # define LUAX_OS_DGUX 140 | #elif defined(__QNXNTO__) 141 | # define LUAX_OS_QNX6 142 | #elif defined(__QNX__) 143 | # define LUAX_OS_QNX 144 | #elif defined(_SEQUENT_) 145 | # define LUAX_OS_DYNIX 146 | #elif defined(_SCO_DS) /* SCO OpenServer 5 + GCC */ 147 | # define LUAX_OS_SCO 148 | #elif defined(__USLC__) /* all SCO platforms + UDK or OUDK */ 149 | # define LUAX_OS_UNIXWARE 150 | #elif defined(__svr4__) && defined(i386) /* Open UNIX 8 + GCC */ 151 | # define LUAX_OS_UNIXWARE 152 | #elif defined(__INTEGRITY) 153 | # define LUAX_OS_INTEGRITY 154 | #elif defined(__MAKEDEPEND__) 155 | #else 156 | # error "Warzone has not been tested on this OS. Please contact warzone-dev@gna.org" 157 | #endif /* LUAX_OS_x */ 158 | 159 | #if defined(LUAX_OS_WIN32) || defined(LUAX_OS_WIN64) 160 | # define LUAX_OS_WIN 161 | #endif /* LUAX_OS_WIN32 */ 162 | 163 | #if defined(LUAX_OS_DARWIN) 164 | # define LUAX_OS_MAC /* LUAX_OS_MAC is mostly for compatibility, but also more clear */ 165 | # define LUAX_OS_MACX /* LUAX_OS_MACX is only for compatibility.*/ 166 | # if defined(LUAX_OS_DARWIN64) 167 | # define LUAX_OS_MAC64 168 | # elif defined(LUAX_OS_DARWIN32) 169 | # define LUAX_OS_MAC32 170 | # endif 171 | #endif /* LUAX_OS_DARWIN */ 172 | 173 | #if defined(LUAX_OS_MSDOS) || defined(LUAX_OS_OS2) || defined(LUAX_OS_WIN) 174 | # undef LUAX_OS_UNIX 175 | #elif !defined(LUAX_OS_UNIX) 176 | # define LUAX_OS_UNIX 177 | #endif /* LUAX_OS_* */ 178 | 179 | 180 | /* 181 | The compiler, must be one of: (LUAX_CC_x) 182 | 183 | MSVC - Microsoft Visual C/C++, Intel C++ for Windows 184 | GNU - GNU C++ 185 | INTEL - Intel C++ for Linux, Intel C++ for Windows 186 | TINYC - Fabrice Bellard's Tiny C Compiler 187 | 188 | Should be sorted most to least authoritative. 189 | */ 190 | 191 | #if defined(_MSC_VER) 192 | # define LUAX_CC_MSVC 193 | /* All ISO C89 compliant compilers _should_ define the macro __STDC__, MSVC 194 | * however is known _not_ to do this, so work around that here. */ 195 | # if !defined(__STDC__) 196 | # define __STDC__ 1 197 | # endif 198 | /* Visual C++.Net issues for _MSC_VER >= 1300 */ 199 | # if _MSC_VER >= 1300 200 | # define LUAX_CC_MSVC_NET 201 | # endif 202 | /* Intel C++ disguising as Visual C++: the `using' keyword avoids warnings */ 203 | # if defined(__INTEL_COMPILER) 204 | # define LUAX_CC_INTEL 205 | # endif 206 | /* x64 does not support mmx intrinsics on windows */ 207 | # if (defined(ZS_OS_WIN64) && defined(_M_X64)) 208 | # undef ZS_HAVE_SSE 209 | # undef ZS_HAVE_SSE2 210 | # undef ZS_HAVE_MMX 211 | # undef ZS_HAVE_3DNOW 212 | # endif 213 | 214 | #elif defined(__GNUC__) 215 | # define LUAX_CC_GNU 216 | # if defined(__MINGW32__) 217 | # define LUAX_CC_MINGW 218 | # endif 219 | # if defined(__INTEL_COMPILER) 220 | /* Intel C++ also masquerades as GCC 3.2.0 */ 221 | # define LUAX_CC_INTEL 222 | # endif 223 | 224 | #elif defined(__TINYC__) 225 | # define LUAX_CC_TINYC 226 | 227 | #else 228 | # error "Warzone has not been tested on this compiler. Please contact warzone-dev@gna.org" 229 | #endif /* LUAX_CC_x */ 230 | 231 | 232 | /* 233 | The window system, must be one of: (LUAX_WS_x) 234 | 235 | MACX - Mac OS X 236 | WIN32 - Windows 237 | X11 - X Window System 238 | QNX - QNX 239 | */ 240 | 241 | #if defined(_WIN32_X11_) 242 | # define LUAX_WS_X11 243 | 244 | #elif defined(LUAX_OS_WIN32) 245 | # define LUAX_WS_WIN32 246 | # if defined(LUAX_OS_WIN64) 247 | # define LUAX_WS_WIN64 248 | # endif 249 | 250 | #elif defined(LUAX_OS_MAC) 251 | # define LUAX_WS_MAC 252 | # define LUAX_WS_MACX 253 | # if defined(LUAX_OS_MAC64) 254 | # define LUAX_WS_MAC64 255 | # elif defined(LUAX_OS_MAC32) 256 | # define LUAX_WS_MAC32 257 | # endif 258 | 259 | #elif defined(LUAX_OS_QNX) 260 | # define LUAX_WS_QNX 261 | 262 | #elif defined(LUAX_OS_UNIX) 263 | # define LUAX_WS_X11 264 | 265 | #else 266 | # error "Warzone has not been tested on this window system. Please contact warzone-dev@gna.org" 267 | #endif /* LUAX_WS_x */ 268 | 269 | #if defined(LUAX_WS_WIN16) || defined(LUAX_WS_WIN32) 270 | # define LUAX_WS_WIN 271 | #endif 272 | 273 | 274 | /* 275 | The supported C standard, must be one of: (LUAX_Cxx) 276 | 277 | 99 - ISO/IEC 9899:1999 / C99 278 | */ 279 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 280 | # define LUAX_C99 281 | #endif /* LUAX_Cxx */ 282 | 283 | /* 284 | The supported C++ standard, must be one of: (LUAX_CXXxx) 285 | 286 | 98 - ISO/IEC 14882:1998 / C++98 287 | */ 288 | #if defined(__cplusplus) 289 | # define LUAX_CXX98 290 | #endif /* LUAX_CXXxx */ 291 | 292 | 293 | /* 294 | Convenience macros to test the versions of gcc. 295 | Copied from glibc's features.h. 296 | */ 297 | #if defined(LUAX_CC_GNU) && defined __GNUC__ && defined __GNUC_MINOR__ 298 | # define LUAX_CC_GNU_PREREQ(maj, min) \ 299 | ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) 300 | #else 301 | # define LUAX_CC_GNU_PREREQ(maj, min) 0 302 | #endif 303 | 304 | 305 | /* 306 | Convenience macros to test the versions of icc. 307 | */ 308 | #if defined(LUAX_CC_INTEL) && defined __ICC 309 | # define LUAX_CC_INTEL_PREREQ(maj, min) \ 310 | ((__ICC) >= ((maj) * 100) + (min)) 311 | #else 312 | # define LUAX_CC_INTEL_PREREQ(maj, min) 0 313 | #endif 314 | 315 | 316 | 317 | 318 | /* ---- Declaration attributes ---- */ 319 | 320 | 321 | /*! 322 | * \def LUAX_DECL_DEPRECATED 323 | * 324 | * The LUAX_DECL_DEPRECATED macro can be used to trigger compile-time warnings 325 | * with newer compilers when deprecated functions are used. 326 | * 327 | * For non-inline functions, the macro gets inserted at front of the 328 | * function declaration, right before the return type: 329 | * 330 | * \code 331 | * LUAX_DECL_DEPRECATED void deprecatedFunctionA(); 332 | * LUAX_DECL_DEPRECATED int deprecatedFunctionB() const; 333 | * \endcode 334 | * 335 | * For functions which are implemented inline, 336 | * the LUAX_DECL_DEPRECATED macro is inserted at the front, right before the return 337 | * type, but after "static", "inline" or "virtual": 338 | * 339 | * \code 340 | * LUAX_DECL_DEPRECATED void deprecatedInlineFunctionA() { .. } 341 | * virtual LUAX_DECL_DEPRECATED int deprecatedInlineFunctionB() { .. } 342 | * static LUAX_DECL_DEPRECATED bool deprecatedInlineFunctionC() { .. } 343 | * inline LUAX_DECL_DEPRECATED bool deprecatedInlineFunctionD() { .. } 344 | * \endcode 345 | * 346 | * You can also mark whole structs or classes as deprecated, by inserting the 347 | * LUAX_DECL_DEPRECATED macro after the struct/class keyword, but before the 348 | * name of the struct/class: 349 | * 350 | * \code 351 | * class LUAX_DECL_DEPRECATED DeprecatedClass { }; 352 | * struct LUAX_DECL_DEPRECATED DeprecatedStruct { }; 353 | * \endcode 354 | * 355 | * \note 356 | * Description copied from KDE4, code copied from Qt4. 357 | * 358 | */ 359 | #if LUAX_CC_GNU_PREREQ(3,2) || LUAX_CC_INTEL_PREREQ(10,0) 360 | # define LUAX_DECL_DEPRECATED __attribute__((__deprecated__)) 361 | #elif defined(LUAX_CC_MSVC) && defined(LUAX_CC_MSVC_NET) 362 | # define LUAX_DECL_DEPRECATED __declspec(deprecated) 363 | #else 364 | # define LUAX_DECL_DEPRECATED 365 | #endif 366 | 367 | 368 | /*! \def LUAX_DECL_FORMAT 369 | * GCC: "The format attribute specifies that a function takes printf, scanf, strftime or strfmon 370 | * style arguments which should be type-checked against a format string." 371 | */ 372 | #if LUAX_CC_GNU_PREREQ(2,5) && !defined(LUAX_CC_INTEL) 373 | # define LUAX_DECL_FORMAT(archetype, string_index, first_to_check) \ 374 | __attribute__((__format__(archetype, string_index, first_to_check))) 375 | #else 376 | # define LUAX_DECL_FORMAT(archetype, string_index, first_to_check) 377 | #endif 378 | 379 | 380 | /*! 381 | * \def LUAX_DECL_NORETURN 382 | * "A few standard library functions, such as abort and exit, cannot return. GCC knows this 383 | * automatically. Some programs define their own functions that never return. 384 | * You can declare them noreturn to tell the compiler this fact." 385 | */ 386 | #if LUAX_CC_GNU_PREREQ(2,5) && !defined(LUAX_CC_INTEL) 387 | # define LUAX_DECL_NORETURN __attribute__((__noreturn__)) 388 | #else 389 | # define LUAX_DECL_NORETURN 390 | #endif 391 | 392 | 393 | /*! 394 | * \def LUAX_DECL_CONST 395 | * GCC: "Many functions do not examine any values except their arguments, and have no effects 396 | * except the return value. Basically this is just slightly more strict class than 397 | * the pure attribute below, since function is not allowed to read global memory." 398 | */ 399 | #if LUAX_CC_GNU_PREREQ(2,5) && !defined(LUAX_CC_INTEL) 400 | # define LUAX_DECL_CONST __attribute__((__const__,__warn_unused_result__)) 401 | #else 402 | # define LUAX_DECL_CONST 403 | #endif 404 | 405 | 406 | /*! 407 | * \def LUAX_DECL_PURE 408 | * GCC: "Many functions have no effects except the return value and their return value depends 409 | * only on the parameters and/or global variables. Such a function can be subject to 410 | * common subexpression elimination and loop optimization just as an arithmetic operator 411 | * would be." 412 | */ 413 | #if LUAX_CC_GNU_PREREQ(2,96) && !defined(LUAX_CC_INTEL) 414 | # define LUAX_DECL_PURE __attribute__((__pure__)) 415 | #else 416 | # define LUAX_DECL_PURE 417 | #endif 418 | 419 | 420 | /*! 421 | * \def LUAX_DECL_UNUSED 422 | * GCC: "This attribute, attached to a function, means that the function is meant to be possibly 423 | * unused. GCC will not produce a warning for this function." 424 | */ 425 | #if LUAX_CC_GNU_PREREQ(3,2) || LUAX_CC_INTEL_PREREQ(10,0) 426 | # define LUAX_DECL_UNUSED __attribute__((__unused__)) 427 | #else 428 | # define LUAX_DECL_UNUSED 429 | #endif 430 | 431 | 432 | /*! 433 | * \def LUAX_DECL_WARN_UNUSED_RESULT 434 | * GCC: "The warn_unused_result attribute causes a warning to be emitted if a caller of the 435 | * function with this attribute does not use its return value. This is useful for 436 | * functions where not checking the result is either a security problem or always a bug, 437 | * such as realloc." 438 | */ 439 | #if defined(LUAX_CC_GNU) && !defined(LUAX_CC_INTEL) 440 | # define LUAX_DECL_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) 441 | #else 442 | # define LUAX_DECL_WARN_UNUSED_RESULT 443 | #endif 444 | 445 | 446 | /*! \def LUAX_DECL_MAY_ALIAS 447 | * GCC: "Accesses to objects with types with this attribute are not subjected to type-based alias 448 | * analysis, but are instead assumed to be able to alias any other type of objects, 449 | * just like the char type. See -fstrict-aliasing for more information on aliasing issues." 450 | */ 451 | #if LUAX_CC_GNU_PREREQ(3,3) && !defined(LUAX_CC_INTEL) 452 | # define LUAX_DECL_MAY_ALIAS __attribute__((__may_alias__)) 453 | #else 454 | # define LUAX_DECL_MAY_ALIAS 455 | #endif 456 | 457 | 458 | /*! 459 | * \def LUAX_DECL_RESTRICT 460 | * Apply the "restrict" keyword found in the C99 revision of the standard. 461 | * The compiler may assume that the memory referenced by a "restrict" pointer is not aliased 462 | * by any other pointer. Thus this forms the opposite of LUAX_DECL_MAY_ALIAS. 463 | */ 464 | #if defined(LUAX_C99) && LUAX_CC_GNU_PREREQ(4,1) && !defined(LUAX_CC_INTEL) 465 | # define LUAX_DECL_RESTRICT restrict 466 | #elif defined(LUAX_CC_MSVC) && defined(LUAX_CC_MSVC_NET) 467 | # define LUAX_DECL_RESTRICT __restrict 468 | #else 469 | # define LUAX_DECL_RESTRICT 470 | #endif 471 | 472 | 473 | /*! \def LUAX_DECL_THREAD 474 | * Declares a variable to be local to the running thread, and not shared between threads. 475 | */ 476 | #if defined(LUAX_CC_GNU) || defined(LUAX_CC_INTEL) 477 | # define LUAX_DECL_THREAD __thread 478 | #elif defined(LUAX_CC_MSVC) 479 | # define LUAX_DECL_THREAD __declspec(thread) 480 | #else 481 | # error "Thread local storage attribute required" 482 | #endif 483 | 484 | 485 | /*! \def LUAX_ASSERT_STATIC_STRING 486 | * Asserts that the given string is statically allocated. 487 | */ 488 | #if defined(__cplusplus) 489 | # include 490 | # define LUAX_ASSERT_STATIC_STRING(_var) assert(typeid(_var) == typeid(char[])) 491 | #elif defined(LUAX_CC_GNU) || defined(LUAX_CC_INTEL) 492 | # define LUAX_ASSERT_STATIC_STRING(_var) assert(__builtin_types_compatible_p(typeof(_var), char[])) 493 | #else 494 | # define LUAX_ASSERT_STATIC_STRING(_var) (void)(_var) 495 | #endif 496 | 497 | 498 | /* ---- Platform specific setup ---- */ 499 | 500 | 501 | #if defined(LUAX_OS_WIN) 502 | # if defined(LUAX_CC_MINGW) 503 | # include 504 | # include 505 | # include 506 | # define _WIN32_IE IE5 507 | /* Required for alloca */ 508 | # include 509 | 510 | # elif defined(LUAX_CC_MSVC) 511 | # if defined(_DEBUG) 512 | # define DEBUG 513 | # define _CRTDBG_MAP_ALLOC 514 | # include 515 | # include 516 | # endif /* _DEBUG */ 517 | # endif /* LUAX_CC_* */ 518 | 519 | # define WIN32_LEAN_AND_MEAN 520 | # define WIN32_EXTRA_LEAN 521 | # include 522 | 523 | # if defined(LUAX_CC_MSVC) 524 | /* notify people we are disabling these warning messages. */ 525 | # pragma message (" *** Warnings 4018,4100,4127,4204,4244,4267,4389 have been squelched. ***") 526 | # pragma warning (disable : 4018) /* Shut up: '>' : signed/unsigned mismatch */ 527 | # pragma warning (disable : 4100) /* Shut up: unreferenced formal parameter (FIXME) */ 528 | # pragma warning (disable : 4127) /* Shut up: conditional expression is constant (eg. "while(0)") */ 529 | # pragma warning (disable : 4204) /* Shut up: non-constant aggregate initializer */ 530 | # pragma warning (disable : 4244) /* Shut up: conversion from 'float' to 'int', possible loss of data */ 531 | # pragma warning (disable : 4267) /* Shut up: conversion from 'size_t' to 'type', possible loss of data */ 532 | # pragma warning (disable : 4389) /* Shut up: '==' : signed/unsigned mismatch */ 533 | 534 | # define strcasecmp _stricmp 535 | # define strncasecmp _strnicmp 536 | # define inline __inline 537 | # define alloca _alloca 538 | # define fileno _fileno 539 | 540 | # define isnan _isnan 541 | # define isfinite _finite 542 | 543 | # define PATH_MAX MAX_PATH 544 | # endif /* LUAX_CC_MSVC */ 545 | 546 | /* Make sure that PATH_MAX is large enough to use as the size for return 547 | * buffers for Windows API calls 548 | */ 549 | # if (PATH_MAX < MAX_PATH) 550 | # undef PATH_MAX 551 | # define PATH_MAX MAX_PATH 552 | # endif 553 | 554 | #elif defined(LUAX_OS_UNIX) 555 | # include 556 | # include 557 | #endif /* LUAX_OS_* */ 558 | 559 | 560 | #if !defined(LUAX_C99) 561 | # if !defined(va_copy) 562 | /** 563 | * Implements the interface of the C99 macro va_copy such that we can use it on 564 | * non-C99 systems as well. 565 | * 566 | * This implementation assumes that va_list is just a pointer to the stack 567 | * frame of the variadic function. This is by far the most common setup, though 568 | * it might not always work. 569 | */ 570 | # define va_copy(dest, src) (void)((dest) = (src)) 571 | # endif /* !va_copy */ 572 | # if !defined(inline) 573 | # define inline __inline 574 | # endif /* !inline */ 575 | #endif /* !LUAX_C99 */ 576 | 577 | 578 | #endif /* WZGLOBAL_H */ 579 | --------------------------------------------------------------------------------