Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // cmd.c -- Quake script command processing module
  21.  
  22. #include "quakedef.h"
  23.  
  24. void Cmd_ForwardToServer (void);
  25.  
  26. #define MAX_ALIAS_NAME  32
  27.  
  28. typedef struct cmdalias_s
  29. {
  30.         struct cmdalias_s       *next;
  31.         char    name[MAX_ALIAS_NAME];
  32.         char    *value;
  33. } cmdalias_t;
  34.  
  35. cmdalias_t      *cmd_alias;
  36.  
  37. int trashtest;
  38. int *trashspot;
  39.  
  40. qboolean        cmd_wait;
  41.  
  42. //=============================================================================
  43.  
  44. /*
  45. ============
  46. Cmd_Wait_f
  47.  
  48. Causes execution of the remainder of the command buffer to be delayed until
  49. next frame.  This allows commands like:
  50. bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
  51. ============
  52. */
  53. void Cmd_Wait_f (void)
  54. {
  55.         cmd_wait = true;
  56. }
  57.  
  58. /*
  59. =============================================================================
  60.  
  61.                                                 COMMAND BUFFER
  62.  
  63. =============================================================================
  64. */
  65.  
  66. sizebuf_t       cmd_text;
  67.  
  68. /*
  69. ============
  70. Cbuf_Init
  71. ============
  72. */
  73. void Cbuf_Init (void)
  74. {
  75.         SZ_Alloc (&cmd_text, 8192);             // space for commands and script files
  76. }
  77.  
  78.  
  79. /*
  80. ============
  81. Cbuf_AddText
  82.  
  83. Adds command text at the end of the buffer
  84. ============
  85. */
  86. void Cbuf_AddText (char *text)
  87. {
  88.         int             l;
  89.        
  90.         l = Q_strlen (text);
  91.  
  92.         if (cmd_text.cursize + l >= cmd_text.maxsize)
  93.         {
  94.                 Con_Printf ("Cbuf_AddText: overflow\n");
  95.                 return;
  96.         }
  97.  
  98.         SZ_Write (&cmd_text, text, Q_strlen (text));
  99. }
  100.  
  101.  
  102. /*
  103. ============
  104. Cbuf_InsertText
  105.  
  106. Adds command text immediately after the current command
  107. Adds a \n to the text
  108. FIXME: actually change the command buffer to do less copying
  109. ============
  110. */
  111. void Cbuf_InsertText (char *text)
  112. {
  113.         char    *temp;
  114.         int             templen;
  115.  
  116. // copy off any commands still remaining in the exec buffer
  117.         templen = cmd_text.cursize;
  118.         if (templen)
  119.         {
  120.                 temp = Z_Malloc (templen);
  121.                 Q_memcpy (temp, cmd_text.data, templen);
  122.                 SZ_Clear (&cmd_text);
  123.         }
  124.         else
  125.                 temp = NULL;    // shut up compiler
  126.                
  127. // add the entire text of the file
  128.         Cbuf_AddText (text);
  129.        
  130. // add the copied off data
  131.         if (templen)
  132.         {
  133.                 SZ_Write (&cmd_text, temp, templen);
  134.                 Z_Free (temp);
  135.         }
  136. }
  137.  
  138. /*
  139. ============
  140. Cbuf_Execute
  141. ============
  142. */
  143. void Cbuf_Execute (void)
  144. {
  145.         int             i;
  146.         char    *text;
  147.         char    line[1024];
  148.         int             quotes;
  149.        
  150.         while (cmd_text.cursize)
  151.         {
  152. // find a \n or ; line break
  153.                 text = (char *)cmd_text.data;
  154.  
  155.                 quotes = 0;
  156.                 for (i=0 ; i< cmd_text.cursize ; i++)
  157.                 {
  158.                         if (text[i] == '"')
  159.                                 quotes++;
  160.                         if ( !(quotes&1) &&  text[i] == ';')
  161.                                 break;  // don't break if inside a quoted string
  162.                         if (text[i] == '\n')
  163.                                 break;
  164.                 }
  165.                        
  166.                                
  167.                 memcpy (line, text, i);
  168.                 line[i] = 0;
  169.                
  170. // delete the text from the command buffer and move remaining commands down
  171. // this is necessary because commands (exec, alias) can insert data at the
  172. // beginning of the text buffer
  173.  
  174.                 if (i == cmd_text.cursize)
  175.                         cmd_text.cursize = 0;
  176.                 else
  177.                 {
  178.                         i++;
  179.                         cmd_text.cursize -= i;
  180.                         Q_memcpy (text, text+i, cmd_text.cursize);
  181.                 }
  182.  
  183. // execute the command line
  184.                 Cmd_ExecuteString (line, src_command);
  185.                
  186.                 if (cmd_wait)
  187.                 {       // skip out while text still remains in buffer, leaving it
  188.                         // for next frame
  189.                         cmd_wait = false;
  190.                         break;
  191.                 }
  192.         }
  193. }
  194.  
  195. /*
  196. ==============================================================================
  197.  
  198.                                                 SCRIPT COMMANDS
  199.  
  200. ==============================================================================
  201. */
  202.  
  203. /*
  204. ===============
  205. Cmd_StuffCmds_f
  206.  
  207. Adds command line parameters as script statements
  208. Commands lead with a +, and continue until a - or another +
  209. quake +prog jctest.qp +cmd amlev1
  210. quake -nosound +cmd amlev1
  211. ===============
  212. */
  213. void Cmd_StuffCmds_f (void)
  214. {
  215.         int             i, j;
  216.         int             s;
  217.         char    *text, *build, c;
  218.                
  219.         if (Cmd_Argc () != 1)
  220.         {
  221.                 Con_Printf ("stuffcmds : execute command line parameters\n");
  222.                 return;
  223.         }
  224.  
  225. // build the combined string to parse from
  226.         s = 0;
  227.         for (i=1 ; i<com_argc ; i++)
  228.         {
  229.                 if (!com_argv[i])
  230.                         continue;               // NEXTSTEP nulls out -NXHost
  231.                 s += Q_strlen (com_argv[i]) + 1;
  232.         }
  233.         if (!s)
  234.                 return;
  235.                
  236.         text = Z_Malloc (s+1);
  237.         text[0] = 0;
  238.         for (i=1 ; i<com_argc ; i++)
  239.         {
  240.                 if (!com_argv[i])
  241.                         continue;               // NEXTSTEP nulls out -NXHost
  242.                 Q_strcat (text,com_argv[i]);
  243.                 if (i != com_argc-1)
  244.                         Q_strcat (text, " ");
  245.         }
  246.        
  247. // pull out the commands
  248.         build = Z_Malloc (s+1);
  249.         build[0] = 0;
  250.        
  251.         for (i=0 ; i<s-1 ; i++)
  252.         {
  253.                 if (text[i] == '+')
  254.                 {
  255.                         i++;
  256.  
  257.                         for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
  258.                                 ;
  259.  
  260.                         c = text[j];
  261.                         text[j] = 0;
  262.                        
  263.                         Q_strcat (build, text+i);
  264.                         Q_strcat (build, "\n");
  265.                         text[j] = c;
  266.                         i = j-1;
  267.                 }
  268.         }
  269.        
  270.         if (build[0])
  271.                 Cbuf_InsertText (build);
  272.        
  273.         Z_Free (text);
  274.         Z_Free (build);
  275. }
  276.  
  277.  
  278. /*
  279. ===============
  280. Cmd_Exec_f
  281. ===============
  282. */
  283. void Cmd_Exec_f (void)
  284. {
  285.         char    *f;
  286.         int             mark;
  287.  
  288.         if (Cmd_Argc () != 2)
  289.         {
  290.                 Con_Printf ("exec <filename> : execute a script file\n");
  291.                 return;
  292.         }
  293.  
  294.         mark = Hunk_LowMark ();
  295.         f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
  296.         if (!f)
  297.         {
  298.                 Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
  299.                 return;
  300.         }
  301.         Con_Printf ("execing %s\n",Cmd_Argv(1));
  302.        
  303.         Cbuf_InsertText (f);
  304.         Hunk_FreeToLowMark (mark);
  305. }
  306.  
  307.  
  308. /*
  309. ===============
  310. Cmd_Echo_f
  311.  
  312. Just prints the rest of the line to the console
  313. ===============
  314. */
  315. void Cmd_Echo_f (void)
  316. {
  317.         int             i;
  318.        
  319.         for (i=1 ; i<Cmd_Argc() ; i++)
  320.                 Con_Printf ("%s ",Cmd_Argv(i));
  321.         Con_Printf ("\n");
  322. }
  323.  
  324. /*
  325. ===============
  326. Cmd_Alias_f
  327.  
  328. Creates a new command that executes a command string (possibly ; seperated)
  329. ===============
  330. */
  331.  
  332. char *CopyString (char *in)
  333. {
  334.         char    *out;
  335.        
  336.         out = Z_Malloc (strlen(in)+1);
  337.         strcpy (out, in);
  338.         return out;
  339. }
  340.  
  341. void Cmd_Alias_f (void)
  342. {
  343.         cmdalias_t      *a;
  344.         char            cmd[1024];
  345.         int                     i, c;
  346.         char            *s;
  347.  
  348.         if (Cmd_Argc() == 1)
  349.         {
  350.                 Con_Printf ("Current alias commands:\n");
  351.                 for (a = cmd_alias ; a ; a=a->next)
  352.                         Con_Printf ("%s : %s\n", a->name, a->value);
  353.                 return;
  354.         }
  355.  
  356.         s = Cmd_Argv(1);
  357.         if (strlen(s) >= MAX_ALIAS_NAME)
  358.         {
  359.                 Con_Printf ("Alias name is too long\n");
  360.                 return;
  361.         }
  362.  
  363.         // if the alias allready exists, reuse it
  364.         for (a = cmd_alias ; a ; a=a->next)
  365.         {
  366.                 if (!strcmp(s, a->name))
  367.                 {
  368.                         Z_Free (a->value);
  369.                         break;
  370.                 }
  371.         }
  372.  
  373.         if (!a)
  374.         {
  375.                 a = Z_Malloc (sizeof(cmdalias_t));
  376.                 a->next = cmd_alias;
  377.                 cmd_alias = a;
  378.         }
  379.         strcpy (a->name, s);   
  380.  
  381. // copy the rest of the command line
  382.         cmd[0] = 0;             // start out with a null string
  383.         c = Cmd_Argc();
  384.         for (i=2 ; i< c ; i++)
  385.         {
  386.                 strcat (cmd, Cmd_Argv(i));
  387.                 if (i != c)
  388.                         strcat (cmd, " ");
  389.         }
  390.         strcat (cmd, "\n");
  391.        
  392.         a->value = CopyString (cmd);
  393. }
  394.  
  395. /*
  396. =============================================================================
  397.  
  398.                                         COMMAND EXECUTION
  399.  
  400. =============================================================================
  401. */
  402.  
  403. typedef struct cmd_function_s
  404. {
  405.         struct cmd_function_s   *next;
  406.         char                                    *name;
  407.         xcommand_t                              function;
  408. } cmd_function_t;
  409.  
  410.  
  411. #define MAX_ARGS                80
  412.  
  413. static  int                     cmd_argc;
  414. static  char            *cmd_argv[MAX_ARGS];
  415. static  char            *cmd_null_string = "";
  416. static  char            *cmd_args = NULL;
  417.  
  418. cmd_source_t    cmd_source;
  419.  
  420.  
  421. static  cmd_function_t  *cmd_functions;         // possible commands to execute
  422.  
  423. /*
  424. ============
  425. Cmd_Init
  426. ============
  427. */
  428. void Cmd_Init (void)
  429. {
  430. //
  431. // register our commands
  432. //
  433.         Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
  434.         Cmd_AddCommand ("exec",Cmd_Exec_f);
  435.         Cmd_AddCommand ("echo",Cmd_Echo_f);
  436.         Cmd_AddCommand ("alias",Cmd_Alias_f);
  437.         Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
  438.         Cmd_AddCommand ("wait", Cmd_Wait_f);
  439. }
  440.  
  441. /*
  442. ============
  443. Cmd_Argc
  444. ============
  445. */
  446. int             Cmd_Argc (void)
  447. {
  448.         return cmd_argc;
  449. }
  450.  
  451. /*
  452. ============
  453. Cmd_Argv
  454. ============
  455. */
  456. char    *Cmd_Argv (int arg)
  457. {
  458.         if ( (unsigned)arg >= cmd_argc )
  459.                 return cmd_null_string;
  460.         return cmd_argv[arg];  
  461. }
  462.  
  463. /*
  464. ============
  465. Cmd_Args
  466. ============
  467. */
  468. char            *Cmd_Args (void)
  469. {
  470.         return cmd_args;
  471. }
  472.  
  473.  
  474. /*
  475. ============
  476. Cmd_TokenizeString
  477.  
  478. Parses the given string into command line tokens.
  479. ============
  480. */
  481. void Cmd_TokenizeString (char *text)
  482. {
  483.         int             i;
  484.        
  485. // clear the args from the last string
  486.         for (i=0 ; i<cmd_argc ; i++)
  487.                 Z_Free (cmd_argv[i]);
  488.                
  489.         cmd_argc = 0;
  490.         cmd_args = NULL;
  491.        
  492.         while (1)
  493.         {
  494. // skip whitespace up to a /n
  495.                 while (*text && *text <= ' ' && *text != '\n')
  496.                 {
  497.                         text++;
  498.                 }
  499.                
  500.                 if (*text == '\n')
  501.                 {       // a newline seperates commands in the buffer
  502.                         text++;
  503.                         break;
  504.                 }
  505.  
  506.                 if (!*text)
  507.                         return;
  508.        
  509.                 if (cmd_argc == 1)
  510.                          cmd_args = text;
  511.                        
  512.                 text = COM_Parse (text);
  513.                 if (!text)
  514.                         return;
  515.  
  516.                 if (cmd_argc < MAX_ARGS)
  517.                 {
  518.                         cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1);
  519.                         Q_strcpy (cmd_argv[cmd_argc], com_token);
  520.                         cmd_argc++;
  521.                 }
  522.         }
  523.        
  524. }
  525.  
  526.  
  527. /*
  528. ============
  529. Cmd_AddCommand
  530. ============
  531. */
  532. void    Cmd_AddCommand (char *cmd_name, xcommand_t function)
  533. {
  534.         cmd_function_t  *cmd;
  535.        
  536.         if (host_initialized)   // because hunk allocation would get stomped
  537.                 Sys_Error ("Cmd_AddCommand after host_initialized");
  538.                
  539. // fail if the command is a variable name
  540.         if (Cvar_VariableString(cmd_name)[0])
  541.         {
  542.                 Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
  543.                 return;
  544.         }
  545.        
  546. // fail if the command already exists
  547.         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  548.         {
  549.                 if (!Q_strcmp (cmd_name, cmd->name))
  550.                 {
  551.                         Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
  552.                         return;
  553.                 }
  554.         }
  555.  
  556.         cmd = Hunk_Alloc (sizeof(cmd_function_t));
  557.         cmd->name = cmd_name;
  558.         cmd->function = function;
  559.         cmd->next = cmd_functions;
  560.         cmd_functions = cmd;
  561. }
  562.  
  563. /*
  564. ============
  565. Cmd_Exists
  566. ============
  567. */
  568. qboolean        Cmd_Exists (char *cmd_name)
  569. {
  570.         cmd_function_t  *cmd;
  571.  
  572.         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  573.         {
  574.                 if (!Q_strcmp (cmd_name,cmd->name))
  575.                         return true;
  576.         }
  577.  
  578.         return false;
  579. }
  580.  
  581.  
  582.  
  583. /*
  584. ============
  585. Cmd_CompleteCommand
  586. ============
  587. */
  588. char *Cmd_CompleteCommand (char *partial)
  589. {
  590.         cmd_function_t  *cmd;
  591.         int                             len;
  592.        
  593.         len = Q_strlen(partial);
  594.        
  595.         if (!len)
  596.                 return NULL;
  597.                
  598. // check functions
  599.         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  600.                 if (!Q_strncmp (partial,cmd->name, len))
  601.                         return cmd->name;
  602.  
  603.         return NULL;
  604. }
  605.  
  606. /*
  607. ============
  608. Cmd_ExecuteString
  609.  
  610. A complete command line has been parsed, so try to execute it
  611. FIXME: lookupnoadd the token to speed search?
  612. ============
  613. */
  614. void    Cmd_ExecuteString (char *text, cmd_source_t src)
  615. {      
  616.         cmd_function_t  *cmd;
  617.         cmdalias_t              *a;
  618.  
  619.         cmd_source = src;
  620.         Cmd_TokenizeString (text);
  621.                        
  622. // execute the command line
  623.         if (!Cmd_Argc())
  624.                 return;         // no tokens
  625.  
  626. // check functions
  627.         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  628.         {
  629.                 if (!Q_strcasecmp (cmd_argv[0],cmd->name))
  630.                 {
  631.                         cmd->function ();
  632.                         return;
  633.                 }
  634.         }
  635.  
  636. // check alias
  637.         for (a=cmd_alias ; a ; a=a->next)
  638.         {
  639.                 if (!Q_strcasecmp (cmd_argv[0], a->name))
  640.                 {
  641.                         Cbuf_InsertText (a->value);
  642.                         return;
  643.                 }
  644.         }
  645.        
  646. // check cvars
  647.         if (!Cvar_Command ())
  648.                 Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
  649.        
  650. }
  651.  
  652.  
  653. /*
  654. ===================
  655. Cmd_ForwardToServer
  656.  
  657. Sends the entire command line over to the server
  658. ===================
  659. */
  660. void Cmd_ForwardToServer (void)
  661. {
  662.         if (cls.state != ca_connected)
  663.         {
  664.                 Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
  665.                 return;
  666.         }
  667.        
  668.         if (cls.demoplayback)
  669.                 return;         // not really connected
  670.  
  671.         MSG_WriteByte (&cls.message, clc_stringcmd);
  672.         if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)
  673.         {
  674.                 SZ_Print (&cls.message, Cmd_Argv(0));
  675.                 SZ_Print (&cls.message, " ");
  676.         }
  677.         if (Cmd_Argc() > 1)
  678.                 SZ_Print (&cls.message, Cmd_Args());
  679.         else
  680.                 SZ_Print (&cls.message, "\n");
  681. }
  682.  
  683.  
  684. /*
  685. ================
  686. Cmd_CheckParm
  687.  
  688. Returns the position (1 to argc-1) in the command's argument list
  689. where the given parameter apears, or 0 if not present
  690. ================
  691. */
  692.  
  693. int Cmd_CheckParm (char *parm)
  694. {
  695.         int i;
  696.        
  697.         if (!parm)
  698.                 Sys_Error ("Cmd_CheckParm: NULL");
  699.  
  700.         for (i = 1; i < Cmd_Argc (); i++)
  701.                 if (! Q_strcasecmp (parm, Cmd_Argv (i)))
  702.                         return i;
  703.                        
  704.         return 0;
  705. }
  706.