PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qcommon/cmd.c

http://bzzwolfmp.googlecode.com/
C | 713 lines | 525 code | 58 blank | 130 comment | 56 complexity | dc3b9255e58ccc598315334b8998ea22 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. ===========================================================================
  3. Return to Castle Wolfenstein multiplayer GPL Source Code
  4. Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (?RTCW MP Source Code?).
  6. RTCW MP Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. RTCW MP Source Code 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. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. // cmd.c -- Quake script command processing module
  21. #include "../game/q_shared.h"
  22. #include "qcommon.h"
  23. #define MAX_CMD_BUFFER 16384
  24. #define MAX_CMD_LINE 1024
  25. typedef struct {
  26. byte *data;
  27. int maxsize;
  28. int cursize;
  29. } cmd_t;
  30. int cmd_wait;
  31. cmd_t cmd_text;
  32. byte cmd_text_buf[MAX_CMD_BUFFER];
  33. //=============================================================================
  34. /*
  35. ============
  36. Cmd_Wait_f
  37. Causes execution of the remainder of the command buffer to be delayed until
  38. next frame. This allows commands like:
  39. bind g "cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster"
  40. ============
  41. */
  42. void Cmd_Wait_f( void ) {
  43. if ( Cmd_Argc() == 2 ) {
  44. cmd_wait = atoi( Cmd_Argv( 1 ) );
  45. } else {
  46. cmd_wait = 1;
  47. }
  48. }
  49. /*
  50. =============================================================================
  51. COMMAND BUFFER
  52. =============================================================================
  53. */
  54. /*
  55. ============
  56. Cbuf_Init
  57. ============
  58. */
  59. void Cbuf_Init( void ) {
  60. cmd_text.data = cmd_text_buf;
  61. cmd_text.maxsize = MAX_CMD_BUFFER;
  62. cmd_text.cursize = 0;
  63. }
  64. /*
  65. ============
  66. Cbuf_AddText
  67. Adds command text at the end of the buffer, does NOT add a final \n
  68. ============
  69. */
  70. void Cbuf_AddText( const char *text ) {
  71. int l;
  72. l = strlen( text );
  73. if ( cmd_text.cursize + l >= cmd_text.maxsize ) {
  74. Com_Printf( "Cbuf_AddText: overflow\n" );
  75. return;
  76. }
  77. memcpy( &cmd_text.data[cmd_text.cursize], text, l );
  78. cmd_text.cursize += l;
  79. }
  80. /*
  81. ============
  82. Cbuf_InsertText
  83. Adds command text immediately after the current command
  84. Adds a \n to the text
  85. ============
  86. */
  87. void Cbuf_InsertText( const char *text ) {
  88. int len;
  89. int i;
  90. len = strlen( text ) + 1;
  91. if ( len + cmd_text.cursize > cmd_text.maxsize ) {
  92. Com_Printf( "Cbuf_InsertText overflowed\n" );
  93. return;
  94. }
  95. // move the existing command text
  96. for ( i = cmd_text.cursize - 1 ; i >= 0 ; i-- ) {
  97. cmd_text.data[ i + len ] = cmd_text.data[ i ];
  98. }
  99. // copy the new text in
  100. memcpy( cmd_text.data, text, len - 1 );
  101. // add a \n
  102. cmd_text.data[ len - 1 ] = '\n';
  103. cmd_text.cursize += len;
  104. }
  105. /*
  106. ============
  107. Cbuf_ExecuteText
  108. ============
  109. */
  110. void Cbuf_ExecuteText( int exec_when, const char *text ) {
  111. switch ( exec_when )
  112. {
  113. case EXEC_NOW:
  114. if ( text && strlen( text ) > 0 ) {
  115. Cmd_ExecuteString( text );
  116. } else {
  117. Cbuf_Execute();
  118. }
  119. break;
  120. case EXEC_INSERT:
  121. Cbuf_InsertText( text );
  122. break;
  123. case EXEC_APPEND:
  124. Cbuf_AddText( text );
  125. break;
  126. default:
  127. Com_Error( ERR_FATAL, "Cbuf_ExecuteText: bad exec_when" );
  128. }
  129. }
  130. /*
  131. ============
  132. Cbuf_Execute
  133. ============
  134. */
  135. void Cbuf_Execute( void ) {
  136. int i;
  137. char *text;
  138. char line[MAX_CMD_LINE];
  139. int quotes;
  140. while ( cmd_text.cursize )
  141. {
  142. if ( cmd_wait ) {
  143. // skip out while text still remains in buffer, leaving it
  144. // for next frame
  145. cmd_wait--;
  146. break;
  147. }
  148. // find a \n or ; line break
  149. text = (char *)cmd_text.data;
  150. quotes = 0;
  151. for ( i = 0 ; i < cmd_text.cursize ; i++ )
  152. {
  153. if ( text[i] == '"' ) {
  154. quotes++;
  155. }
  156. if ( !( quotes & 1 ) && text[i] == ';' ) {
  157. break; // don't break if inside a quoted string
  158. }
  159. if ( text[i] == '\n' || text[i] == '\r' ) {
  160. break;
  161. }
  162. }
  163. if ( i >= ( MAX_CMD_LINE - 1 ) ) {
  164. i = MAX_CMD_LINE - 1;
  165. }
  166. memcpy( line, text, i );
  167. line[i] = 0;
  168. // delete the text from the command buffer and move remaining commands down
  169. // this is necessary because commands (exec) can insert data at the
  170. // beginning of the text buffer
  171. if ( i == cmd_text.cursize ) {
  172. cmd_text.cursize = 0;
  173. } else
  174. {
  175. i++;
  176. cmd_text.cursize -= i;
  177. memmove( text, text + i, cmd_text.cursize );
  178. }
  179. // execute the command line
  180. Cmd_ExecuteString( line );
  181. }
  182. }
  183. /*
  184. ==============================================================================
  185. SCRIPT COMMANDS
  186. ==============================================================================
  187. */
  188. /*
  189. ===============
  190. Cmd_Exec_f
  191. ===============
  192. */
  193. void Cmd_Exec_f( void ) {
  194. char *f;
  195. int len;
  196. char filename[MAX_QPATH];
  197. if ( Cmd_Argc() != 2 ) {
  198. Com_Printf( "exec <filename> : execute a script file\n" );
  199. return;
  200. }
  201. Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) );
  202. COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
  203. len = FS_ReadFile( filename, (void **)&f );
  204. if ( !f ) {
  205. Com_Printf( "couldn't exec %s\n",Cmd_Argv( 1 ) );
  206. return;
  207. }
  208. Com_Printf( "execing %s\n",Cmd_Argv( 1 ) );
  209. Cbuf_InsertText( f );
  210. FS_FreeFile( f );
  211. }
  212. /*
  213. ===============
  214. Cmd_Vstr_f
  215. Inserts the current value of a variable as command text
  216. ===============
  217. */
  218. void Cmd_Vstr_f( void ) {
  219. char *v;
  220. if ( Cmd_Argc() != 2 ) {
  221. Com_Printf( "vstr <variablename> : execute a variable command\n" );
  222. return;
  223. }
  224. v = Cvar_VariableString( Cmd_Argv( 1 ) );
  225. Cbuf_InsertText( va( "%s\n", v ) );
  226. }
  227. /*
  228. ===============
  229. Cmd_Echo_f
  230. Just prints the rest of the line to the console
  231. ===============
  232. */
  233. void Cmd_Echo_f( void ) {
  234. int i;
  235. for ( i = 1 ; i < Cmd_Argc() ; i++ )
  236. Com_Printf( "%s ",Cmd_Argv( i ) );
  237. Com_Printf( "\n" );
  238. }
  239. /*
  240. =============================================================================
  241. COMMAND EXECUTION
  242. =============================================================================
  243. */
  244. typedef struct cmd_function_s
  245. {
  246. struct cmd_function_s *next;
  247. char *name;
  248. xcommand_t function;
  249. } cmd_function_t;
  250. static int cmd_argc;
  251. static char *cmd_argv[MAX_STRING_TOKENS]; // points into cmd_tokenized
  252. static char cmd_tokenized[BIG_INFO_STRING + MAX_STRING_TOKENS]; // will have 0 bytes inserted
  253. static char cmd_cmd[BIG_INFO_STRING]; // the original command we received (no token processing)
  254. static cmd_function_t *cmd_functions; // possible commands to execute
  255. /*
  256. ============
  257. Cmd_Argc
  258. ============
  259. */
  260. int Cmd_Argc( void ) {
  261. return cmd_argc;
  262. }
  263. /*
  264. ============
  265. Cmd_Argv
  266. ============
  267. */
  268. char *Cmd_Argv( int arg ) {
  269. if ( (unsigned)arg >= cmd_argc ) {
  270. return "";
  271. }
  272. return cmd_argv[arg];
  273. }
  274. /*
  275. ============
  276. Cmd_ArgvBuffer
  277. The interpreted versions use this because
  278. they can't have pointers returned to them
  279. ============
  280. */
  281. void Cmd_ArgvBuffer( int arg, char *buffer, int bufferLength ) {
  282. Q_strncpyz( buffer, Cmd_Argv( arg ), bufferLength );
  283. }
  284. /*
  285. ============
  286. Cmd_Args
  287. Returns a single string containing argv(1) to argv(argc()-1)
  288. ============
  289. */
  290. char *Cmd_Args( void ) {
  291. static char cmd_args[MAX_STRING_CHARS];
  292. int i;
  293. cmd_args[0] = 0;
  294. for ( i = 1 ; i < cmd_argc ; i++ ) {
  295. strcat( cmd_args, cmd_argv[i] );
  296. if ( i != cmd_argc - 1 ) {
  297. strcat( cmd_args, " " );
  298. }
  299. }
  300. return cmd_args;
  301. }
  302. /*
  303. ============
  304. Cmd_Args
  305. Returns a single string containing argv(arg) to argv(argc()-1)
  306. ============
  307. */
  308. char *Cmd_ArgsFrom( int arg ) {
  309. static char cmd_args[BIG_INFO_STRING];
  310. int i;
  311. cmd_args[0] = 0;
  312. if ( arg < 0 ) {
  313. arg = 0;
  314. }
  315. for ( i = arg ; i < cmd_argc ; i++ ) {
  316. strcat( cmd_args, cmd_argv[i] );
  317. if ( i != cmd_argc - 1 ) {
  318. strcat( cmd_args, " " );
  319. }
  320. }
  321. return cmd_args;
  322. }
  323. /*
  324. ============
  325. Cmd_ArgsBuffer
  326. The interpreted versions use this because
  327. they can't have pointers returned to them
  328. ============
  329. */
  330. void Cmd_ArgsBuffer( char *buffer, int bufferLength ) {
  331. Q_strncpyz( buffer, Cmd_Args(), bufferLength );
  332. }
  333. /*
  334. ============
  335. Cmd_Cmd
  336. Retrieve the unmodified command string
  337. For rcon use when you want to transmit without altering quoting
  338. ATVI Wolfenstein Misc #284
  339. ============
  340. */
  341. char *Cmd_Cmd() {
  342. return cmd_cmd;
  343. }
  344. /*
  345. ============
  346. Cmd_TokenizeString
  347. Parses the given string into command line tokens.
  348. The text is copied to a seperate buffer and 0 characters
  349. are inserted in the apropriate place, The argv array
  350. will point into this temporary buffer.
  351. ============
  352. */
  353. void Cmd_TokenizeString( const char *text_in ) {
  354. const char *text;
  355. char *textOut;
  356. // clear previous args
  357. cmd_argc = 0;
  358. if ( !text_in ) {
  359. return;
  360. }
  361. Q_strncpyz( cmd_cmd, text_in, sizeof( cmd_cmd ) );
  362. text = text_in;
  363. textOut = cmd_tokenized;
  364. while ( 1 ) {
  365. if ( cmd_argc == MAX_STRING_TOKENS ) {
  366. return; // this is usually something malicious
  367. }
  368. while ( 1 ) {
  369. // skip whitespace
  370. while ( *text && *text <= ' ' ) {
  371. text++;
  372. }
  373. if ( !*text ) {
  374. return; // all tokens parsed
  375. }
  376. // skip // comments
  377. if ( text[0] == '/' && text[1] == '/' ) {
  378. return; // all tokens parsed
  379. }
  380. // skip /* */ comments
  381. if ( text[0] == '/' && text[1] == '*' ) {
  382. while ( *text && ( text[0] != '*' || text[1] != '/' ) ) {
  383. text++;
  384. }
  385. if ( !*text ) {
  386. return; // all tokens parsed
  387. }
  388. text += 2;
  389. } else {
  390. break; // we are ready to parse a token
  391. }
  392. }
  393. // handle quoted strings
  394. if ( *text == '"' ) {
  395. cmd_argv[cmd_argc] = textOut;
  396. cmd_argc++;
  397. text++;
  398. while ( *text && *text != '"' ) {
  399. *textOut++ = *text++;
  400. }
  401. *textOut++ = 0;
  402. if ( !*text ) {
  403. return; // all tokens parsed
  404. }
  405. text++;
  406. continue;
  407. }
  408. // regular token
  409. cmd_argv[cmd_argc] = textOut;
  410. cmd_argc++;
  411. // skip until whitespace, quote, or command
  412. while ( *text > ' ' ) {
  413. if ( text[0] == '"' ) {
  414. break;
  415. }
  416. if ( text[0] == '/' && text[1] == '/' ) {
  417. break;
  418. }
  419. // skip /* */ comments
  420. if ( text[0] == '/' && text[1] == '*' ) {
  421. break;
  422. }
  423. *textOut++ = *text++;
  424. }
  425. *textOut++ = 0;
  426. if ( !*text ) {
  427. return; // all tokens parsed
  428. }
  429. }
  430. }
  431. /*
  432. ============
  433. Cmd_AddCommand
  434. ============
  435. */
  436. void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) {
  437. cmd_function_t *cmd;
  438. // fail if the command already exists
  439. for ( cmd = cmd_functions ; cmd ; cmd = cmd->next ) {
  440. if ( !strcmp( cmd_name, cmd->name ) ) {
  441. // allow completion-only commands to be silently doubled
  442. if ( function != NULL ) {
  443. Com_Printf( "Cmd_AddCommand: %s already defined\n", cmd_name );
  444. }
  445. return;
  446. }
  447. }
  448. // use a small malloc to avoid zone fragmentation
  449. cmd = S_Malloc( sizeof( cmd_function_t ) );
  450. cmd->name = CopyString( cmd_name );
  451. cmd->function = function;
  452. cmd->next = cmd_functions;
  453. cmd_functions = cmd;
  454. }
  455. /*
  456. ============
  457. Cmd_RemoveCommand
  458. ============
  459. */
  460. void Cmd_RemoveCommand( const char *cmd_name ) {
  461. cmd_function_t *cmd, **back;
  462. back = &cmd_functions;
  463. while ( 1 ) {
  464. cmd = *back;
  465. if ( !cmd ) {
  466. // command wasn't active
  467. return;
  468. }
  469. if ( !strcmp( cmd_name, cmd->name ) ) {
  470. *back = cmd->next;
  471. if ( cmd->name ) {
  472. Z_Free( cmd->name );
  473. }
  474. Z_Free( cmd );
  475. return;
  476. }
  477. back = &cmd->next;
  478. }
  479. }
  480. /*
  481. ============
  482. Cmd_CommandCompletion
  483. ============
  484. */
  485. void Cmd_CommandCompletion( void ( *callback )(const char *s) ) {
  486. cmd_function_t *cmd;
  487. for ( cmd = cmd_functions ; cmd ; cmd = cmd->next ) {
  488. callback( cmd->name );
  489. }
  490. }
  491. /*
  492. ============
  493. Cmd_ExecuteString
  494. A complete command line has been parsed, so try to execute it
  495. ============
  496. */
  497. void Cmd_ExecuteString( const char *text ) {
  498. cmd_function_t *cmd, **prev;
  499. // execute the command line
  500. Cmd_TokenizeString( text );
  501. if ( !Cmd_Argc() ) {
  502. return; // no tokens
  503. }
  504. // check registered command functions
  505. for ( prev = &cmd_functions ; *prev ; prev = &cmd->next ) {
  506. cmd = *prev;
  507. if ( !Q_stricmp( cmd_argv[0],cmd->name ) ) {
  508. // rearrange the links so that the command will be
  509. // near the head of the list next time it is used
  510. *prev = cmd->next;
  511. cmd->next = cmd_functions;
  512. cmd_functions = cmd;
  513. // perform the action
  514. if ( !cmd->function ) {
  515. // let the cgame or game handle it
  516. break;
  517. } else {
  518. cmd->function();
  519. }
  520. return;
  521. }
  522. }
  523. // check cvars
  524. if ( Cvar_Command() ) {
  525. return;
  526. }
  527. // check client game commands
  528. if ( com_cl_running && com_cl_running->integer && CL_GameCommand() ) {
  529. return;
  530. }
  531. // check server game commands
  532. if ( com_sv_running && com_sv_running->integer && SV_GameCommand() ) {
  533. return;
  534. }
  535. // check ui commands
  536. if ( com_cl_running && com_cl_running->integer && UI_GameCommand() ) {
  537. return;
  538. }
  539. // send it as a server command if we are connected
  540. // this will usually result in a chat message
  541. CL_ForwardCommandToServer( text );
  542. }
  543. /*
  544. ============
  545. Cmd_List_f
  546. ============
  547. */
  548. void Cmd_List_f( void ) {
  549. cmd_function_t *cmd;
  550. int i;
  551. char *match;
  552. if ( Cmd_Argc() > 1 ) {
  553. match = Cmd_Argv( 1 );
  554. } else {
  555. match = NULL;
  556. }
  557. i = 0;
  558. for ( cmd = cmd_functions ; cmd ; cmd = cmd->next ) {
  559. if ( match && !Com_Filter( match, cmd->name, qfalse ) ) {
  560. continue;
  561. }
  562. Com_Printf( "%s\n", cmd->name );
  563. i++;
  564. }
  565. Com_Printf( "%i commands\n", i );
  566. }
  567. /*
  568. ============
  569. Cmd_Init
  570. ============
  571. */
  572. void Cmd_Init( void ) {
  573. Cmd_AddCommand( "cmdlist",Cmd_List_f );
  574. Cmd_AddCommand( "exec",Cmd_Exec_f );
  575. Cmd_AddCommand( "vstr",Cmd_Vstr_f );
  576. Cmd_AddCommand( "echo",Cmd_Echo_f );
  577. Cmd_AddCommand( "wait", Cmd_Wait_f );
  578. }