script.cc (7257B)
1 #include "common.h" 2 #include "platform.h" 3 #include "ui.h" 4 5 #include "platform_time.h" 6 7 #if PLATFORM_WINDOWS 8 #include "lua/lua.hpp" 9 #else 10 #include <lua.hpp> 11 #endif 12 13 #include "whereami/whereami.h" 14 15 #if LUA_VERSION_NUM < 502 16 #define luaL_len lua_objlen 17 #endif 18 19 static constexpr u8 lua_combined[] = { 20 #include "../build/lua_combined.h" 21 }; 22 23 static lua_State * lua; 24 25 static int inputHandlerIdx = LUA_NOREF; 26 static int macroHandlerIdx = LUA_NOREF; 27 static int closeHandlerIdx = LUA_NOREF; 28 static int socketHandlerIdx = LUA_NOREF; 29 static int intervalHandlerIdx = LUA_NOREF; 30 31 static void pcall( int args, const char * err ) { 32 if( lua_pcall( lua, args, 0, 1 ) ) { 33 printf( "%s: %s\n", err, lua_tostring( lua, -1 ) ); 34 exit( 1 ); 35 } 36 37 assert( lua_gettop( lua ) == 1 ); 38 } 39 40 void script_handleInput( const char * buffer, int len ) { 41 ZoneScoped; 42 43 assert( inputHandlerIdx != LUA_NOREF ); 44 45 lua_rawgeti( lua, LUA_REGISTRYINDEX, inputHandlerIdx ); 46 lua_pushlstring( lua, buffer, len ); 47 48 pcall( 1, "script_handleInput" ); 49 } 50 51 void script_doMacro( const char * key, int len, bool shift, bool ctrl, bool alt ) { 52 ZoneScoped; 53 54 // printf( "macro %s%s%s%.*s\n", shift ? "s" : "", ctrl ? "c" : "", alt ? "a" : "", len, key ); 55 // fflush( stdout ); 56 57 assert( macroHandlerIdx != LUA_NOREF ); 58 59 lua_rawgeti( lua, LUA_REGISTRYINDEX, macroHandlerIdx ); 60 61 lua_pushlstring( lua, key, len ); 62 63 lua_pushboolean( lua, shift ); 64 lua_pushboolean( lua, ctrl ); 65 lua_pushboolean( lua, alt ); 66 67 pcall( 4, "script_doMacro" ); 68 } 69 70 void script_handleClose() { 71 ZoneScoped; 72 73 assert( closeHandlerIdx != LUA_NOREF ); 74 75 lua_rawgeti( lua, LUA_REGISTRYINDEX, closeHandlerIdx ); 76 pcall( 0, "script_handleClose" ); 77 } 78 79 void script_socketData( void * sock, const char * data, size_t len ) { 80 ZoneScoped; 81 82 assert( socketHandlerIdx != LUA_NOREF ); 83 84 lua_rawgeti( lua, LUA_REGISTRYINDEX, socketHandlerIdx ); 85 86 lua_pushlightuserdata( lua, sock ); 87 if( data == NULL ) { 88 lua_pushnil( lua ); 89 } 90 else { 91 lua_pushlstring( lua, data, len ); 92 } 93 94 pcall( 2, "script_socketData" ); 95 } 96 97 void script_fire_intervals() { 98 ZoneScoped; 99 100 assert( intervalHandlerIdx != LUA_NOREF ); 101 102 lua_rawgeti( lua, LUA_REGISTRYINDEX, intervalHandlerIdx ); 103 pcall( 0, "script_fire_intervals" ); 104 } 105 106 namespace { 107 108 template< typename F > 109 static void generic_print( F * f, lua_State * L ) { 110 const char * str = luaL_checkstring( L, 1 ); 111 size_t len = luaL_len( L, 1 ); 112 113 Colour fg = Colour( luaL_checkinteger( L, 2 ) ); 114 Colour bg = Colour( luaL_checkinteger( L, 3 ) ); 115 bool bold = lua_toboolean( L, 4 ); 116 117 f( str, len, fg, bg, bold ); 118 } 119 120 extern "C" int mud_connect( lua_State * L ) { 121 const char * host = luaL_checkstring( L, 1 ); 122 int port = luaL_checkinteger( L, 2 ); 123 124 const char * err; 125 void * sock = platform_connect( &err, host, port ); 126 if( sock != NULL ) { 127 lua_pushlightuserdata( lua, sock ); 128 return 1; 129 } 130 131 lua_pushnil( lua ); 132 lua_pushstring( lua, err ); 133 134 return 2; 135 } 136 137 extern "C" int mud_send( lua_State * L ) { 138 luaL_argcheck( L, lua_isuserdata( L, 1 ) == 1, 1, "expected socket" ); 139 void * sock = lua_touserdata( L, 1 ); 140 141 const char * data = luaL_checkstring( L, 2 ); 142 size_t len = luaL_len( L, 2 ); 143 144 platform_send( sock, data, len ); 145 146 return 0; 147 } 148 149 extern "C" int mud_close( lua_State * L ) { 150 luaL_argcheck( L, lua_isuserdata( L, 1 ) == 1, 1, "expected socket" ); 151 void * sock = lua_touserdata( L, 1 ); 152 153 platform_close( sock ); 154 155 return 0; 156 } 157 158 extern "C" int mud_printMain( lua_State * L ) { 159 generic_print( ui_main_print, L ); 160 return 0; 161 } 162 163 extern "C" int mud_newlineMain( lua_State * L ) { 164 ui_main_newline(); 165 return 0; 166 } 167 168 extern "C" int mud_printChat( lua_State * L ) { 169 generic_print( ui_chat_print, L ); 170 return 0; 171 } 172 173 extern "C" int mud_newlineChat( lua_State * L ) { 174 ui_chat_newline(); 175 return 0; 176 } 177 178 extern "C" int mud_setStatus( lua_State * L ) { 179 luaL_argcheck( L, lua_type( L, 1 ) == LUA_TTABLE, 1, "expected function" ); 180 181 size_t len = luaL_len( L, 1 ); 182 183 ui_clear_status(); 184 185 for( size_t i = 0; i < len; i++ ) { 186 lua_pushnumber( L, i + 1 ); 187 lua_gettable( L, 1 ); 188 189 lua_pushliteral( L, "text" ); 190 lua_gettable( L, 2 ); 191 size_t seglen; 192 const char * str = lua_tolstring( L, -1, &seglen ); 193 194 lua_pushliteral( L, "fg" ); 195 lua_gettable( L, 2 ); 196 const Colour fg = Colour( lua_tointeger( L, -1 ) ); 197 198 lua_pushliteral( L, "bold" ); 199 lua_gettable( L, 2 ); 200 const bool bold = lua_toboolean( L, -1 ); 201 202 for( size_t j = 0; j < seglen; j++ ) { 203 ui_statusAdd( str[ j ], fg, bold ); 204 } 205 206 lua_pop( L, 4 ); 207 } 208 209 return 0; 210 } 211 212 extern "C" int mud_setHandlers( lua_State * L ) { 213 luaL_argcheck( L, lua_type( L, 1 ) == LUA_TFUNCTION, 1, "expected function" ); 214 luaL_argcheck( L, lua_type( L, 2 ) == LUA_TFUNCTION, 2, "expected function" ); 215 luaL_argcheck( L, lua_type( L, 3 ) == LUA_TFUNCTION, 3, "expected function" ); 216 luaL_argcheck( L, lua_type( L, 4 ) == LUA_TFUNCTION, 4, "expected function" ); 217 luaL_argcheck( L, lua_type( L, 5 ) == LUA_TFUNCTION, 5, "expected function" ); 218 219 intervalHandlerIdx = luaL_ref( L, LUA_REGISTRYINDEX ); 220 socketHandlerIdx = luaL_ref( L, LUA_REGISTRYINDEX ); 221 closeHandlerIdx = luaL_ref( L, LUA_REGISTRYINDEX ); 222 macroHandlerIdx = luaL_ref( L, LUA_REGISTRYINDEX ); 223 inputHandlerIdx = luaL_ref( L, LUA_REGISTRYINDEX ); 224 225 return 0; 226 } 227 228 extern "C" int mud_urgent( lua_State * L ) { 229 ui_urgent(); 230 return 0; 231 } 232 233 extern "C" int mud_now( lua_State * L ) { 234 lua_pushnumber( L, get_time() ); 235 return 1; 236 } 237 238 extern "C" int mud_set_font( lua_State * L ) { 239 const char * name = luaL_checkstring( L, 1 ); 240 int size = luaL_checkinteger( L, 2 ); 241 242 bool ok = ui_set_font( name, size ); 243 244 lua_pushboolean( lua, ok ); 245 246 return 1; 247 } 248 249 } // anon namespace 250 251 static void push_exe_dir( lua_State * L ) { 252 int len = wai_getExecutablePath( NULL, 0, NULL ); 253 if( len == -1 ) { 254 lua_pushliteral( L, "." ); 255 } 256 else { 257 char * buf = alloc_many< char >( len ); 258 259 int dirlen; 260 if( wai_getExecutablePath( buf, len, &dirlen ) == -1 ) { 261 lua_pushliteral( L, "." ); 262 } 263 else { 264 lua_pushlstring( L, buf, dirlen ); 265 } 266 267 free( buf ); 268 } 269 } 270 271 #if PLATFORM_WINDOWS 272 extern "C" int luaopen_lpeg( lua_State * L ); 273 extern "C" int luaopen_lfs( lua_State * L ); 274 #endif 275 276 void script_init() { 277 ZoneScoped; 278 279 lua = luaL_newstate(); 280 luaL_openlibs( lua ); 281 282 #if PLATFORM_WINDOWS 283 luaL_requiref( lua, "lpeg", luaopen_lpeg, 0 ); 284 lua_pop( lua, 1 ); 285 286 luaL_requiref( lua, "lfs", luaopen_lfs, 0 ); 287 lua_pop( lua, 1 ); 288 #endif 289 290 lua_getglobal( lua, "debug" ); 291 lua_getfield( lua, -1, "traceback" ); 292 lua_remove( lua, -2 ); 293 294 if( luaL_loadbufferx( lua, ( const char * ) lua_combined, sizeof( lua_combined ), "main", "t" ) != LUA_OK ) { 295 printf( "Error reading main.lua: %s\n", lua_tostring( lua, -1 ) ); 296 exit( 1 ); 297 } 298 299 lua_pushcfunction( lua, mud_printMain ); 300 lua_pushcfunction( lua, mud_newlineMain ); 301 lua_pushcfunction( lua, mud_printChat ); 302 lua_pushcfunction( lua, mud_newlineChat ); 303 304 lua_pushcfunction( lua, mud_setHandlers ); 305 306 lua_pushcfunction( lua, mud_urgent ); 307 308 lua_pushcfunction( lua, mud_setStatus ); 309 310 lua_pushcfunction( lua, mud_connect ); 311 lua_pushcfunction( lua, mud_send ); 312 lua_pushcfunction( lua, mud_close ); 313 314 lua_pushcfunction( lua, mud_now ); 315 316 lua_pushcfunction( lua, mud_set_font ); 317 318 push_exe_dir( lua ); 319 320 pcall( 13, "Error running main.lua" ); 321 } 322 323 void script_term() { 324 lua_close( lua ); 325 }