UFO: Alien Invasion
Doxygen documentation generating
cl_lua.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2023 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "cl_lua.h"
27 
28 #include "../../shared/cxx.h"
29 #include "../../shared/defines.h"
30 #include "../../shared/shared.h"
31 #include "../../common/hashtable.h"
32 #include "../../common/filesys.h"
33 
34 /* global lua state for ui-lua interfacing */
35 lua_State* cl_luastate = nullptr;
36 /* hash map for storing callback references */
38 
39 /* references to SWIG generated lua bindings */
40 extern "C" int luaopen_ufo (lua_State *L);
41 
47 static int CL_UfoModuleLoader (lua_State* L) {
48  /* this function is called by lua with the module name on the stack */
49  char module[256];
50  char errmsg[512];
51  const char* name = lua_tostring(L, -1);
52  byte* buffer;
53 
54  /* initialize */
55  memset(module, 0, sizeof(module));
56  Com_sprintf(module, sizeof(module), "ufos/ui/%s", name);
57  memset(errmsg, 0, sizeof(errmsg));
58 
59  /* find the module using ufo's filesystem */
60  Com_Printf("Lua custom-loading module: %s\n", name);
61  int len = FS_LoadFile(module, &buffer);
62  if (len != -1) {
63  /* found, the contents of the file is now present in buffer */
64  /* load the contents into the lua state */
65  if (luaL_loadbuffer(L, (const char*) buffer, len, module) == 0) {
66  return 1;
67  } else {
68  /* push error string onto the stack */
69  sprintf(errmsg, "Lua custom-loader error: cannot load module named [%s]:\n\t%s\n", module, lua_tostring(L, -1));
70  Com_Printf("%s", errmsg);
71  lua_pushstring(L, errmsg);
72  }
73  } else {
74  /* push error string onto the stack */
75  sprintf(errmsg, "Lua custom-loader error: cannot find module named [%s]\n", module);
76  Com_Printf("%s", errmsg);
77  lua_pushstring(L, errmsg);
78  }
79  /* an error occured, return 0*/
80  return 0;
81 }
82 
83 
88 static void CL_InsertModuleLoader (lua_State* L) {
89  /* save stack position */
90  int pos = lua_gettop(L);
91 
92  lua_getglobal(L, "package");
93  if (lua_isnil(L, -1))
94  luaL_error(L, "Can't register searcher: package table does not exist.");
95  lua_getfield(L, -1, "searchers");
96  if (lua_isnil(L, -1))
97  luaL_error(L, "Can't register searcher: package.searchers table does not exist.");
98 
99  /* remote the 'package' entry from the stack */
100  lua_remove(L, -2);
101 
102  /* the lua stack now only holds the field 'loaders' on top */
103  /* next, determine the number of loaders by counting (lua doesn't have a function for this) */
104  int nloaders = 0;
105  /* lua_next pushes a (key, value) pair using the first entry following the key already on the stack;
106  in this case we start with a nil key so lua_next will return the first (key,value) pair in the table
107  of loaders */
108  lua_pushnil(L);
109  /* if lua_next reaches the end, it returns 0 */
110  while (lua_next(L, -2) != 0) {
111  /* lua_next has pushed a (key,value) pair on the stack; remove the value, keep the key
112  for the next iteration */
113  lua_pop(L, 1);
114  nloaders++;
115  }
116 
117  /* now that we have the number of entries in the 'loaders' table, we can add our own loader */
118  lua_pushinteger(L, nloaders + 1);
119  lua_pushcfunction(L, CL_UfoModuleLoader);
120  lua_rawset(L, -3);
121 
122  /* restore stack position */
123  lua_settop(L, pos);
124 }
125 
126 
130 void CL_InitLua (void) {
131  /* clean up old state */
132  if (cl_luastate) {
133  CL_ShutdownLua();
134  }
135 
136  /* initialize new lua environment dedicated to the ui */
137  cl_luastate = luaL_newstate();
138 
139  /* add basic lua libraries to the lua environment */
140  luaL_openlibs(cl_luastate);
141 
142  /* insert custom module loader */
144 
145  /* add the ufo module -> exposes common functions */
147 
148  /* initialize hash table for onload callback mechanism */
149  cl_callback = HASH_NewTable(true, true, true);
150 }
151 
155 void CL_ShutdownLua (void) {
156  if (cl_luastate) {
158  lua_close(cl_luastate);
159  cl_luastate = nullptr;
160  }
161 }
162 
166 lua_State* CL_GetLuaState (void) {
167  return cl_luastate;
168 }
169 
175 void CL_RegisterCallback (const char* key, LUA_FUNCTION fnc) {
176  int regvalue = (int) fnc;
177  /* store regvalue into the list of handlers */
178  int len = strlen(key);
179  if (len > 0) {
180  HASH_Insert(cl_callback, key, len, &regvalue, sizeof(regvalue));
181  }
182  else {
183  Com_Printf("CL_RegisterCallback: lua callback registration error: script name has zero length!\n");
184  }
185 }
186 
194 void CL_ExecuteCallback (lua_State *L, const char* key) {
195  /* look up the handler */
196  void *value = HASH_Get(cl_callback, key, strlen (key));
197  if (value) {
198  int regvalue = * ((int*)value);
199  lua_rawgeti(L, LUA_REGISTRYINDEX, regvalue);
200  if (lua_pcall(L, 0, 0, 0) != 0) {
201  Com_Printf("lua error: %s\n", lua_tostring(cl_luastate, -1));
202  };
203  }
204 }
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
lua_State * CL_GetLuaState(void)
Returns the lua state for the client side.
Definition: cl_lua.cpp:166
void CL_ShutdownLua(void)
Shutdown the ui-lua interfacing environment.
Definition: cl_lua.cpp:155
lua_State * cl_luastate
Definition: cl_lua.cpp:35
void HASH_DeleteTable(hashTable_s **t)
Deletes a hash table and sets the pointer to NULL.
Definition: hashtable.cpp:351
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
hashTable_s * HASH_NewTable(bool ownsKeys, bool ownsValues, bool duplicateOverwrite)
Creates a new hash table and sets it initial capacity.
Definition: hashtable.cpp:287
int luaopen_ufo(lua_State *L)
unsigned int key
Definition: cl_input.cpp:68
void CL_InitLua(void)
Initializes the ui-lua interfacing environment.
Definition: cl_lua.cpp:130
static void CL_InsertModuleLoader(lua_State *L)
This function adds loader to the lua table of module loaders that enables lua to access the ufo files...
Definition: cl_lua.cpp:88
void * HASH_Get(hashTable_s *t, const void *key, int nkey)
Returns the value for a given key.
Definition: hashtable.cpp:467
static int CL_UfoModuleLoader(lua_State *L)
Loader that enables the lua files to access .ufo files through the ufo filesystem.
Definition: cl_lua.cpp:47
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
int LUA_FUNCTION
callback signatures for functions defined in Lua
Definition: scripts_lua.h:45
The hash table structure, contains an array of buckets being indexed by the hash function.
Definition: hashtable.cpp:96
void CL_ExecuteCallback(lua_State *L, const char *key)
Calls the registered lua onload callback function.
Definition: cl_lua.cpp:194
uint8_t byte
Definition: ufotypes.h:34
void CL_RegisterCallback(const char *key, LUA_FUNCTION fnc)
Registers a lua callback function with a key.
Definition: cl_lua.cpp:175
bool HASH_Insert(hashTable_s *t, const void *key, int nkey, const void *value, int nvalue)
Inserts a new value with given key into the hash table.
Definition: hashtable.cpp:369
hashTable_s * cl_callback
Definition: cl_lua.cpp:37