Advertisement
Guest User

Untitled

a guest
Sep 5th, 2011
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.35 KB | None | 0 0
  1. /*
  2. Copyright (C) 2009-2011 Cor Entertainment, LLC
  3. Copyright assigned by Max Eliaser
  4.  
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13.  
  14. See the GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19. */
  20.  
  21. #include <lua5.1/lua.h>
  22. #include <lua5.1/lualib.h>
  23. #include <lua5.1/lauxlib.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. /*#include "qcommon.h"*/
  28. #include "../server/server.h"
  29.  
  30. cvar_t *ldeveloper;
  31.  
  32.  
  33. #define curr_console (con_curDebuggedCon?con_curDebuggedCon:con_curAlternateCon)
  34.  
  35. #ifdef PARANOID
  36. static void qlua_checkConsole (lua_State *luaVM_local) {
  37.     int scriptID;
  38.     lua_getglobal (luaVM_local, "selfID");
  39.     scriptID = lua_tointeger(luaVM_local, -1);
  40.     assert (scriptID == (curr_console));
  41. }
  42. #else
  43. #define qlua_checkConsole(x)
  44. #endif
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51. //functions which start with "LUA" (all-caps) are used within scripts
  52. //functions which start with "qlua" (no caps) are lua-related but not used directly within scripts.
  53.  
  54.  
  55.  
  56. void qlua_clearStack (lua_State **luaVM_local ) {
  57.     lua_settop (*luaVM_local, 0);
  58. }
  59.  
  60. //for debugging
  61. static void qlua_printStack (lua_State *L) {
  62.     int i;
  63.     for (i = 1; i <= lua_gettop(L); i++)
  64.         printf ("%d: %s\n", i, lua_typename(L, lua_type(L, i)));
  65.     printf ("===========\n");
  66. }
  67.  
  68.  
  69.  
  70.  
  71.  
  72. /*
  73. This state will not contain or run any actual code.
  74.  
  75. On other scripts, a single table called sharedTable will show up, but that
  76. table will be empty; instead, it will be made to act as a proxy for a table
  77. called sharedTable on luaVMShared which has all the actual data.
  78. */
  79. lua_State *luaVMShared;
  80.  
  81.  
  82.  
  83.  
  84.  
  85. //wrapper around the addText function for use within lua scripts
  86. int LUA_Cbuf_AddText (lua_State *luaVM_local) {
  87.     int sID;
  88.     const char *msg;
  89.    
  90.     qlua_checkConsole (luaVM_local);
  91.    
  92.     sID = curr_console-1;
  93.    
  94.     if (!lua_isstring (luaVM_local, 1)){
  95.         lua_pushstring (luaVM_local, "qconsole_send: Wrong agument type!\n");
  96.         lua_error (luaVM_local);
  97.     }
  98.    
  99.     msg = lua_tostring (luaVM_local, 1);
  100.    
  101.     if (scripts[sID]->cmd_console.cursize + strlen(msg) > scripts[sID]->cmd_console.maxsize){
  102.         lua_pushstring (luaVM_local, "qconsole_send: Overflow!\n");
  103.         lua_error (luaVM_local);
  104.     }
  105.    
  106.     Abuf_AddText (&(scripts[sID]->cmd_console), (char *)msg);
  107.     return 0;
  108. }
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115. int LUA_Cbuf_Execute (lua_State *luaVM_local) {
  116.     int         tmpCon  = con_toPrintTo;
  117.     qboolean    discard = false;
  118.     int         starting_consize;
  119.     int         sID;
  120.    
  121.     qlua_checkConsole (luaVM_local);
  122.    
  123.     if ( !strcmp ( lua_tostring (luaVM_local, 1), "private" ) ){
  124.         con_toPrintTo = curr_console;
  125.     } else if ( !strcmp (lua_tostring (luaVM_local, 1), "public" ) ){
  126.         if (dedicated->integer)
  127.             broadcastInstead = true;
  128.         con_toPrintTo = DISPLAYED_CONSOLE;
  129.     } else if ( !strcmp ( lua_tostring (luaVM_local, 1), "devel" ) ){
  130.         //If ldeveloper is 1, "devel" is like "public," otherwise output goes
  131.         //to the bit bucket. For info which is useful for developers but is
  132.         //confusing for everyone else.
  133.         if (!ldeveloper->integer){
  134.             discard = true;
  135.             con_toPrintTo = curr_console;
  136.         } else
  137.             con_toPrintTo = DISPLAYED_CONSOLE;
  138.     } else {
  139.         retassert(lua_pushfstring   (   luaVM_local, "qconsole_do: argument 1 must be 'devel,' 'private' or 'public.'\n(Got %s)\n",
  140.                                         lua_tostring(luaVM_local, 1)  ) );
  141.         lua_error (luaVM_local);
  142.     }
  143.    
  144.     sID = curr_console-1;
  145.    
  146.     if (discard)
  147.         starting_consize = scripts[sID]->con_output.cursize;
  148.    
  149.     if (!Abuf_Execute (&(scripts[sID]->cmd_console))) {
  150.         lua_pushstring (luaVM_local, "qconsole_do: one of the commands failed.\n");
  151.         lua_error (luaVM_local);
  152.     }
  153.        
  154.    
  155.     if (discard)
  156.         scripts[sID]->con_output.cursize = starting_consize;
  157.    
  158.     con_toPrintTo = tmpCon;
  159.     broadcastInstead = false;
  160.     return 0;
  161. }
  162.  
  163.  
  164.  
  165.  
  166.  
  167. int LUA_con_alternateOutput (lua_State *luaVM_local) {
  168.     if ( strcmp (lua_tostring (luaVM_local, 1), "private" ) == 0 ){
  169.         SZ_Clip(&(scripts[curr_console-1]->con_output));
  170.         lua_pushstring (luaVM_local, scripts[curr_console-1]->con_output_buf);
  171.     } else if ( strcmp (lua_tostring (luaVM_local, 1), "public" ) == 0 ){
  172.         lua_pushstring (luaVM_local, (char *)(publicMsgOutputBuf + scripts[curr_console-1]->publicMsgItemsReadSoFar));
  173.         scripts[curr_console-1]->publicMsgItemsReadSoFar = publicMsgOutputBufCount;
  174.     } else {
  175.         retassert(lua_pushfstring   (   luaVM_local, "qconsole_get: argument 1 must be either 'private' or 'public.'\n(Got %s)\n",
  176.                                         lua_tostring(luaVM_local, 1)  ) );
  177.         lua_error (luaVM_local);
  178.     }
  179.     return 1;
  180. }
  181.  
  182.  
  183.  
  184.  
  185. int LUA_clr_con_alternateOutput (lua_State *luaVM_local) {
  186.     qlua_checkConsole (luaVM_local);
  187.     scripts[curr_console-1]->con_output.cursize = 0;
  188.     return 0;
  189. }
  190.  
  191.  
  192.  
  193.  
  194. /*
  195. Equivalent to the following Lua code:
  196.     function getStringFromCommand (command)
  197.         qconsole_do ("devel")
  198.         qconsole_clr()
  199.         qconsole_send (command)
  200.         qconsole_do ("private")
  201.         local text = string.sub(qconsole_get ("private"), 1, -2) -- get rid of extraneous newline
  202.         qconsole_clr()
  203.         return text
  204.     end
  205. Since crossing the boundary between C and Lua is expensive, and this is
  206. probably the single most common function used by scripts, it's worthwhile to
  207. write it in C.
  208. */
  209. int LUA_getStringFromCommand (lua_State *luaVM_local) {
  210.     int sID;
  211.     qboolean discard = false;
  212.     const char *msg;
  213.     int tmpCon = con_toPrintTo;
  214.    
  215.     qlua_checkConsole (luaVM_local);
  216.    
  217.     if (!lua_isstring (luaVM_local, 1)) {
  218.         lua_pushstring (luaVM_local, "getStringFromCommand: Wrong argument type!\n");
  219.         lua_error (luaVM_local);
  220.     }
  221.    
  222.     sID = curr_console-1;
  223.    
  224.     if (!ldeveloper->integer) {
  225.         discard = true;
  226.         con_toPrintTo = curr_console;
  227.     } else
  228.         con_toPrintTo = DISPLAYED_CONSOLE;
  229.    
  230.     if (!Abuf_Execute (&(scripts[sID]->cmd_console))) {
  231.         lua_pushstring (luaVM_local, "getStringFromCommand: one of the previous commands failed.\n");
  232.         lua_error (luaVM_local);
  233.     }
  234.    
  235.     scripts[sID]->con_output.cursize = 0;
  236.     con_toPrintTo = curr_console;
  237.  
  238.     msg = lua_tostring (luaVM_local, 1);
  239.    
  240.     if (scripts[sID]->cmd_console.cursize + strlen(msg) > scripts[sID]->cmd_console.maxsize){
  241.         lua_pushstring (luaVM_local, "getStringFromCommand: Overflow!\n");
  242.         lua_error (luaVM_local);
  243.     }
  244.    
  245.     Abuf_AddText (&(scripts[sID]->cmd_console), (char *)msg);
  246.    
  247.     if (!Abuf_Execute (&(scripts[sID]->cmd_console))) {
  248.         lua_pushstring (luaVM_local, "getStringFromCommand: one of the commands failed.\n");
  249.         lua_error (luaVM_local);
  250.     }
  251.    
  252.     scripts[sID]->con_output.cursize--; //get rid of extraneous newline
  253.     SZ_Clip(&(scripts[sID]->con_output));
  254.    
  255.     lua_pushstring (luaVM_local, scripts[sID]->con_output_buf);
  256.    
  257.     scripts[sID]->con_output.cursize = 0;
  258.     con_toPrintTo = tmpCon;
  259.    
  260.     return 1;
  261. }
  262.    
  263.  
  264.  
  265.  
  266. int LUA_com_printf (lua_State *luaVM_local) {
  267.     const char  *s;
  268.     int         tmpCon = con_toPrintTo;
  269.    
  270.     s = lua_tostring (luaVM_local, 1);
  271.    
  272.     if (!s){
  273.         lua_pushstring (luaVM_local, "qconsole_print: must have exactly 1 argument which must be a string.\n");
  274.         lua_error (luaVM_local);
  275.     }
  276.    
  277.     con_toPrintTo = DISPLAYED_CONSOLE;
  278.     Com_Printf ("%s\n", s);
  279.     con_toPrintTo = tmpCon;
  280.    
  281.     return 0;
  282. }
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303. qboolean qlua_interrupt ( int scriptID, char *message ){
  304.     int old_currentInterruptedScript;
  305.     lua_State **luaVM_local;
  306.     qboolean ret;
  307.     if (con_curDebuggedCon){
  308.         return true;
  309.         printf ("WTPF?!\n");
  310.     }
  311.     old_currentInterruptedScript = currentInterruptedScript;
  312.     luaVM_local = &((scripts[scriptID])->luaVM);
  313.     currentInterruptedScript = scriptID+1;
  314.     assert (lua_checkstack ( *luaVM_local, 8));
  315.     lua_getglobal ( *luaVM_local, "_interrupt");
  316.     lua_pushstring ( *luaVM_local, message);
  317.     if (qlua_pcall (currentInterruptedScript, 1, 0)){
  318.         fprintf (stderr, "Debugger started on interrupting %d with message %s\n", currentInterruptedScript, message);
  319.         currentInterruptedScript = old_currentInterruptedScript;
  320.         return false;
  321.     }
  322.     ret = Abuf_Execute(&(scripts[currentInterruptedScript-1]->cmd_console));
  323.     qlua_clearStack (luaVM_local);
  324.     currentInterruptedScript = old_currentInterruptedScript;
  325.     return ret;
  326. }
  327.  
  328.  
  329.  
  330.  
  331.  
  332. void qlua_initVM ( lua_State **luaVM_local) {
  333.     char *old_package_path;
  334.     int env_stackpos; //stack position of the thread's environment table
  335.     //create a new thread and its environment table
  336.     lua_getglobal       (luaVMShared, "states");
  337.     *luaVM_local = lua_newthread (luaVMShared);
  338.     lua_pushinteger     (luaVMShared, con_curAlternateCon);
  339.     lua_settable        (luaVMShared, -3);
  340.     lua_pop             (luaVMShared, 1);
  341.     lua_pushthread      (*luaVM_local);
  342.     lua_newtable        (*luaVM_local);
  343.     lua_setfenv         (*luaVM_local, -2);
  344.     lua_getfenv         (*luaVM_local, -1);
  345.     luaL_openlibs       (*luaVM_local);
  346.     env_stackpos = lua_gettop (*luaVM_local);
  347.     //install all the standard libraries into the thread's environment table
  348.     lua_getglobal       (luaVMShared, "installg");
  349.     lua_xmove           (luaVMShared, *luaVM_local, 1);
  350.     lua_pushvalue       (*luaVM_local, env_stackpos);
  351.     lua_call            (*luaVM_local, 1, 0);
  352.    
  353.     //add the "require" path
  354.     lua_getglobal   ( *luaVM_local, "package" );
  355.     lua_getfield    ( *luaVM_local, -1, "path" );
  356.     old_package_path = lua_tostring ( *luaVM_local, -1 );
  357.     retassert( lua_pushfstring (    *luaVM_local,
  358.                                     "%s;data1/lua/?;./data1/lua/?.lua;./arena/lua/?;./arena/lua/?.lua;"
  359.                                     "./data1/lua/include/?;./data1/lua/include/?.lua;"
  360.                                     "./arena/lua/include/?;./arena/lua/include/?.lua;"
  361.                                     "./data1/lua/auxlib/?;./data1/lua/auxlib/?.lua;"
  362.                                     "./arena/lua/auxlib/?;./arena/lua/auxlib/?.lua;"
  363.                                     "./data1/lua/sys/?;./data1/lua/sys/?.lua;", //no arena/sys!
  364.                                     old_package_path )  );
  365.     lua_setfield    ( *luaVM_local, -3, "path" );
  366.     lua_checkstack      (*luaVM_local, 5);
  367.  
  368.     //lpack library
  369.     luaopen_pack        (*luaVM_local);
  370.     //register custom functions (API)
  371.     lua_register        ( *luaVM_local, "qconsole_send",        LUA_Cbuf_AddText);
  372.     lua_register        ( *luaVM_local, "qconsole_do",          LUA_Cbuf_Execute);
  373.     lua_register        ( *luaVM_local, "qconsole_get",         LUA_con_alternateOutput);
  374.     lua_register        ( *luaVM_local, "qconsole_clr",         LUA_clr_con_alternateOutput);
  375.     lua_register        ( *luaVM_local, "qconsole_print",       LUA_com_printf);
  376.     lua_register        ( *luaVM_local, "getStringFromCommand", LUA_getStringFromCommand);
  377.     // create the sharedTable proxy    
  378.     lua_getglobal       ( luaVMShared, "sharedTable");
  379.     lua_xmove           ( luaVMShared, *luaVM_local, 1);
  380.     lua_setfield        ( *luaVM_local, env_stackpos, "sharedTable");
  381.     //other misc variables we define go here
  382.     lua_pushnumber      ( *luaVM_local,         con_curAlternateCon);
  383.     lua_setfield        ( *luaVM_local, env_stackpos, "selfID");
  384.    
  385.     luaL_loadfile   ( *luaVM_local, "data1/lua/sys/interrupt_wrapper.lua" );
  386.     if (lua_resume   ( *luaVM_local, 0))
  387.         fprintf (stderr, "error loading interrupt wrapper!\n");
  388.    
  389.     //new print() function
  390.     luaL_loadfile   ( *luaVM_local, "data1/lua/sys/qprint.lua" );
  391.     if (lua_resume   ( *luaVM_local, 0))
  392.         fprintf (stderr, "Couldn't override print()!\n");
  393.    
  394.     //initialize debugger module
  395.     qlua_init_debugger  ( *luaVM_local );
  396. }
  397.  
  398.  
  399. qboolean qlua_doFile (int scriptID, char *scriptName ) {
  400.     lua_State **luaVM_local;
  401.     int old_currentInterruptedScript = currentInterruptedScript;
  402.     luaVM_local = &((scripts[scriptID])->luaVM);
  403.     lua_settop (*luaVM_local, 0);
  404.     currentInterruptedScript = scriptID+1;
  405.     //load print as the error handler for printing any syntax errors found
  406.     //during parsing
  407.     lua_getglobal (*luaVM_local, "print");
  408.     luaL_loadfile (*luaVM_local, scriptName);
  409.     if (lua_resume (*luaVM_local, 0)){
  410.         lua_call (*luaVM_local, 1, 0);
  411.         Abuf_Execute(&(scripts[currentInterruptedScript-1]->cmd_console));
  412.         currentInterruptedScript = old_currentInterruptedScript;
  413.         return false;
  414.     }
  415.     strncpy (scripts[currentInterruptedScript-1]->scriptName, scriptName, 1024);
  416.     currentInterruptedScript = old_currentInterruptedScript;
  417.     lua_getglobal (*luaVM_local, "noinit");
  418.     if (lua_isnil(*luaVM_local, -1) && !(int)lua_tonumber(*luaVM_local, -1) )
  419.         return qlua_interrupt (scriptID, "init");
  420.     return true;
  421. }
  422.  
  423.  
  424.  
  425.  
  426. void qlua_close (int scriptID) {
  427.     lua_getglobal ( luaVMShared, "states" );
  428.     lua_pushinteger ( luaVMShared, scriptID+1 );
  429.     lua_pushnil ( luaVMShared );
  430.     lua_settable ( luaVMShared, -3 );
  431.     lua_pop ( luaVMShared, 1 );
  432.     lua_getfield ( luaVMShared, LUA_REGISTRYINDEX, "_LOADED" );
  433.     lua_pushnil ( luaVMShared );
  434.     lua_rawseti ( luaVMShared, -2, scriptID+1);
  435.     lua_pop ( luaVMShared, 1 );
  436. }
  437.  
  438.  
  439.  
  440.  
  441. static int LUA_getSelfID (lua_State *luaVM_local) {
  442.     lua_pushinteger (luaVM_local, currentInterruptedScript);
  443.     return 1;
  444. }
  445.  
  446.  
  447.  
  448.  
  449. void qlua_init (void){
  450.     ldeveloper = Cvar_Get ("ldeveloper", "1", 0); //eventually will be 0
  451.     luaVMShared = lua_open();
  452.     luaL_openlibs (luaVMShared);
  453.    
  454.     luaL_loadfile   ( luaVMShared, "data1/lua/sys/prepare_thread.lua" );
  455.     if (lua_pcall   ( luaVMShared, 0, 0, 0))
  456.         fprintf (stderr, "error loading thread preparer!\n");
  457.    
  458.     //Force the "require" function to load the same library multiple times.
  459.     //This is done by spoofing the existence of separate versions of
  460.     //registry._LOADED for each script.
  461.     lua_getfield        (luaVMShared, LUA_REGISTRYINDEX, "_LOADED");
  462.     lua_getglobal       (luaVMShared, "create_loaded_metatable");
  463.     lua_pushcfunction   (luaVMShared, LUA_getSelfID);
  464.     lua_call            (luaVMShared, 1, 1);
  465.     lua_setmetatable    (luaVMShared, -2);
  466.     lua_pop             (luaVMShared, 1);
  467.    
  468.     lua_newtable (luaVMShared);
  469.     lua_setglobal (luaVMShared, "sharedTable");
  470.     lua_newtable (luaVMShared);
  471.     lua_setglobal (luaVMShared, "states");
  472.     qlua_initPcallThread ();
  473. }
  474.  
  475. void qlua_shutdown (void){
  476.     lua_close (luaVMShared);
  477.     qlua_shutdownPcallThread ();
  478. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement