Guest User

Untitled

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