home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / cmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  12.5 KB  |  706 lines

  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.   cmd_function_t  *cmd;
  616.   cmdalias_t    *a;
  617.  
  618.   cmd_source = src;
  619.   Cmd_TokenizeString (text);
  620.       
  621. // execute the command line
  622.   if (!Cmd_Argc())
  623.     return;   // no tokens
  624.  
  625. // check functions
  626.   for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
  627.   {
  628.     if (!Q_strcasecmp (cmd_argv[0],cmd->name))
  629.     {
  630.       cmd->function ();
  631.       return;
  632.     }
  633.   }
  634.  
  635. // check alias
  636.   for (a=cmd_alias ; a ; a=a->next)
  637.   {
  638.     if (!Q_strcasecmp (cmd_argv[0], a->name))
  639.     {
  640.       Cbuf_InsertText (a->value);
  641.       return;
  642.     }
  643.   }
  644.   
  645. // check cvars
  646.   if (!Cvar_Command ())
  647.     Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
  648.   
  649. }
  650.  
  651.  
  652. /*
  653. ===================
  654. Cmd_ForwardToServer
  655.  
  656. Sends the entire command line over to the server
  657. ===================
  658. */
  659. void Cmd_ForwardToServer (void)
  660. {
  661.   if (cls.state != ca_connected)
  662.   {
  663.     Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
  664.     return;
  665.   }
  666.   
  667.   if (cls.demoplayback)
  668.     return;   // not really connected
  669.  
  670.   MSG_WriteByte (&cls.message, clc_stringcmd);
  671.   if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)
  672.   {
  673.     SZ_Print (&cls.message, Cmd_Argv(0));
  674.     SZ_Print (&cls.message, " ");
  675.   }
  676.   if (Cmd_Argc() > 1)
  677.     SZ_Print (&cls.message, Cmd_Args());
  678.   else
  679.     SZ_Print (&cls.message, "\n");
  680. }
  681.  
  682.  
  683. /*
  684. ================
  685. Cmd_CheckParm
  686.  
  687. Returns the position (1 to argc-1) in the command's argument list
  688. where the given parameter apears, or 0 if not present
  689. ================
  690. */
  691.  
  692. int Cmd_CheckParm (char *parm)
  693. {
  694.   int i;
  695.   
  696.   if (!parm)
  697.     Sys_Error ("Cmd_CheckParm: NULL");
  698.  
  699.   for (i = 1; i < Cmd_Argc (); i++)
  700.     if (! Q_strcasecmp (parm, Cmd_Argv (i)))
  701.       return i;
  702.       
  703.   return 0;
  704. }
  705.