cmd.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196
  1. /*
  2. Copyright (C) 2004 Michael Liebscher <johnnycanuck@users.sourceforge.net>
  3. Copyright (C) 1997-2001 Id Software, Inc.
  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. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. /*
  17. * cmd.c: Script command processing module.
  18. *
  19. * Author: Michael Liebscher
  20. *
  21. * Acknowledgement:
  22. * This code was derived from Quake II, and was originally
  23. * written by Id Software, Inc.
  24. *
  25. */
  26. #include "../wolfiphone.h"
  27. //void Cmd_ForwardToServer( void );
  28. #define MAX_ALIAS_NAME 32
  29. typedef struct cmdalias_s
  30. {
  31. struct cmdalias_s *next;
  32. char name[ MAX_ALIAS_NAME ];
  33. W32 id;
  34. char *value;
  35. } cmdalias_t;
  36. cmdalias_t *cmd_alias;
  37. _boolean cmd_wait;
  38. #define ALIAS_LOOP_COUNT 16
  39. int alias_count; // for detecting runaway loops
  40. //=============================================================================
  41. /*
  42. -----------------------------------------------------------------------------
  43. Function: Cmd_Wait_f -Wait command.
  44. Parameters: Nothing.
  45. Returns: Nothing.
  46. Notes:
  47. Causes execution of the remainder of the command buffer to be delayed until
  48. next frame. This allows commands like:
  49. bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
  50. -----------------------------------------------------------------------------
  51. */
  52. PRIVATE void Cmd_Wait_f( void )
  53. {
  54. cmd_wait = true;
  55. }
  56. /*
  57. =============================================================================
  58. COMMAND BUFFER
  59. =============================================================================
  60. */
  61. PRIVATE sizebuf_t cmd_text;
  62. PRIVATE W8 cmd_text_buf[ 8192 ];
  63. PRIVATE W8 defer_text_buf[ 8192 ];
  64. /*
  65. -----------------------------------------------------------------------------
  66. Function: Cmd_Init -Allocates an initial text buffer that will grow as needed.
  67. Parameters: Nothing.
  68. Returns: Nothing.
  69. Notes: This must be called before using command buffer.
  70. -----------------------------------------------------------------------------
  71. */
  72. PRIVATE void Cbuf_Init( void )
  73. {
  74. SZ_Init( &cmd_text, cmd_text_buf, sizeof( cmd_text_buf ) );
  75. }
  76. /*
  77. -----------------------------------------------------------------------------
  78. Function: Cbuf_AddText -Adds command text at the end of the buffer.
  79. Parameters: text -[in] Ponter to NUL-terminated string.
  80. Returns: Nothing.
  81. Notes:
  82. -----------------------------------------------------------------------------
  83. */
  84. PUBLIC void Cbuf_AddText( const char *text )
  85. {
  86. W32 length;
  87. length = strlen( text );
  88. if( cmd_text.cursize + length >= cmd_text.maxsize )
  89. {
  90. Com_Printf( "Cbuf_AddText: overflow\n" );
  91. return;
  92. }
  93. SZ_Write( &cmd_text, (void *)text, length );
  94. }
  95. /*
  96. -----------------------------------------------------------------------------
  97. Function: Cbuf_InsertText -Adds command text immediately after the current
  98. command.
  99. Parameters: text -[in] Command text to add to buffer.
  100. Returns: Nothing.
  101. Notes:
  102. Adds a \n to the text
  103. FIXME: actually change the command buffer to do less copying
  104. -----------------------------------------------------------------------------
  105. */
  106. PUBLIC void Cbuf_InsertText( char *text )
  107. {
  108. char *temp;
  109. size_t templen;
  110. // copy off any commands still remaining in the exec buffer
  111. templen = cmd_text.cursize;
  112. if( templen )
  113. {
  114. temp = Z_Malloc( templen );
  115. memcpy( temp, cmd_text.data, templen );
  116. SZ_Clear( &cmd_text );
  117. }
  118. else
  119. {
  120. temp = NULL; // shut up compiler
  121. }
  122. // add the entire text of the file
  123. Cbuf_AddText( text );
  124. // add the copied off data
  125. if( templen )
  126. {
  127. SZ_Write( &cmd_text, temp, templen );
  128. Z_Free( temp );
  129. }
  130. }
  131. /*
  132. -----------------------------------------------------------------------------
  133. Function: Cbuf_CopyToDefer -Copy command buffer to defer buffer.
  134. Parameters: Nothing.
  135. Returns: Nothing.
  136. Notes:
  137. -----------------------------------------------------------------------------
  138. */
  139. PUBLIC void Cbuf_CopyToDefer( void )
  140. {
  141. memcpy( defer_text_buf, cmd_text_buf, cmd_text.cursize );
  142. defer_text_buf[ cmd_text.cursize ] = 0;
  143. cmd_text.cursize = 0;
  144. }
  145. /*
  146. -----------------------------------------------------------------------------
  147. Function: Cbuf_InsertFromDefer -Insert commands from defer buffer to command
  148. buffer.
  149. Parameters: Nothing.
  150. Returns: Nothing.
  151. Notes:
  152. -----------------------------------------------------------------------------
  153. */
  154. PUBLIC void Cbuf_InsertFromDefer( void )
  155. {
  156. Cbuf_InsertText( (char *)defer_text_buf );
  157. defer_text_buf[ 0 ] = 0;
  158. }
  159. /*
  160. -----------------------------------------------------------------------------
  161. Function: Cbuf_ExecuteText -Execute string.
  162. Parameters: exec_when -[in] see execwhen_t definition.
  163. text -[in] string with command to execute.
  164. Returns:
  165. Notes:
  166. -----------------------------------------------------------------------------
  167. */
  168. PUBLIC void Cbuf_ExecuteText( execwhen_t exec_when, char *text )
  169. {
  170. switch( exec_when )
  171. {
  172. case EXEC_NOW:
  173. Cmd_ExecuteString( text );
  174. break;
  175. case EXEC_INSERT:
  176. Cbuf_InsertText( text );
  177. break;
  178. case EXEC_APPEND:
  179. Cbuf_AddText( text );
  180. break;
  181. default:
  182. Com_DPrintf( "Cbuf_ExecuteText: bad exec_when" );
  183. }
  184. }
  185. /*
  186. -----------------------------------------------------------------------------
  187. Function: Cbuf_Execute -execute string from command buffer.
  188. Parameters: Nothing.
  189. Returns: Nothing.
  190. Notes:
  191. -----------------------------------------------------------------------------
  192. */
  193. PUBLIC void Cbuf_Execute( void )
  194. {
  195. int i;
  196. char *text;
  197. char line[ 1024 ];
  198. int quotes;
  199. alias_count = 0; // don't allow infinite alias loops
  200. while( cmd_text.cursize )
  201. {
  202. // find a \n or ; line break
  203. text = (char *)cmd_text.data;
  204. quotes = 0;
  205. for( i = 0; i < cmd_text.cursize; ++i )
  206. {
  207. if( text[ i ] == '"' )
  208. {
  209. quotes++;
  210. }
  211. if( !(quotes & 1) && text[ i ] == ';' )
  212. {
  213. break; // don't break if inside a quoted string
  214. }
  215. if( text[ i ] == '\n' || text[ i ] == '#' )
  216. {
  217. break; // break on a newline or a hash mark
  218. }
  219. }
  220. memcpy( line, text, i );
  221. line[ i ] = '\0'; // NUL-terminate string
  222. // delete the text from the command buffer and move remaining commands down
  223. // this is necessary because commands (exec, alias) can insert data at the
  224. // beginning of the text buffer
  225. if( i == cmd_text.cursize )
  226. {
  227. cmd_text.cursize = 0;
  228. }
  229. else
  230. {
  231. i++;
  232. cmd_text.cursize -= i;
  233. memmove( text, text+i, cmd_text.cursize );
  234. }
  235. // execute the command line
  236. Cmd_ExecuteString( line );
  237. if( cmd_wait )
  238. {
  239. // skip out while text still remains in buffer, leaving it
  240. // for next frame
  241. cmd_wait = false;
  242. break;
  243. }
  244. }
  245. }
  246. /*
  247. -----------------------------------------------------------------------------
  248. Function: Cbuf_AddEarlyCommands -Adds command line parameters as script
  249. statements.
  250. Parameters: clear -[in] Remove item from global array com_argv.
  251. Returns: Nothing.
  252. Notes:
  253. Adds command line parameters as script statements
  254. Commands lead with a +, and continue until another +
  255. Set commands are added early, so they are guaranteed to be set
  256. before the client and server initialize for the first time.
  257. Other commands are added late, after all initialization is complete.
  258. -----------------------------------------------------------------------------
  259. */
  260. PUBLIC void Cbuf_AddEarlyCommands( _boolean clear )
  261. {
  262. int i;
  263. char *s;
  264. for( i = 0; i < COM_Argc(); ++i )
  265. {
  266. s = COM_Argv( i );
  267. if( strcmp( s, "+set" ) )
  268. continue;
  269. Cbuf_AddText( va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
  270. if( clear )
  271. {
  272. COM_ClearArgv( i );
  273. COM_ClearArgv( i+1 );
  274. COM_ClearArgv( i+2 );
  275. }
  276. i += 2;
  277. }
  278. }
  279. /*
  280. -----------------------------------------------------------------------------
  281. Function: Cbuf_AddLateCommands -Adds command line parameters as script
  282. statements.
  283. Parameters: Nothing.
  284. Returns: true if any late commands were added, otherwise false.
  285. Notes:
  286. Commands lead with a + and continue until another + or -
  287. application.exe +map amlev1
  288. Returns true if any late commands were added, which
  289. will keep the demoloop from immediately starting
  290. -----------------------------------------------------------------------------
  291. */
  292. PUBLIC _boolean Cbuf_AddLateCommands( void )
  293. {
  294. int i, j;
  295. int s;
  296. char *text, *build, c;
  297. int argc;
  298. _boolean ret;
  299. // build the combined string to parse from
  300. s = 0;
  301. argc = COM_Argc();
  302. for( i = 1; i < argc; ++i )
  303. {
  304. s += strlen( COM_Argv( i ) ) + 1;
  305. }
  306. if( ! s )
  307. {
  308. return false;
  309. }
  310. text = Z_Malloc( s + 1 );
  311. text[ 0 ] = '\0'; // Start with a NUL-terminated string.
  312. for( i = 1; i < argc; ++i )
  313. {
  314. my_strlcat( text, COM_Argv( i ), s );
  315. if( i != argc-1 )
  316. {
  317. my_strlcat( text, " ", s );
  318. }
  319. }
  320. // pull out the commands
  321. build = Z_Malloc( s + 1 );
  322. build[ 0 ] = '\0'; // Start with a NUL-terminated string.
  323. for( i = 0; i < s-1; ++i )
  324. {
  325. if( text[ i ] == '+' )
  326. {
  327. i++;
  328. for( j = i ; (text[ j ] != '+') && (text[ j ] != '-') && (text[ j ] != 0) ; j++ )
  329. ;
  330. c = text[ j ];
  331. text[ j ] = 0;
  332. my_strlcat( build, text+i, s+1 );
  333. my_strlcat( build, "\n", s+1 );
  334. text[ j ] = c;
  335. i = j - 1;
  336. }
  337. }
  338. ret = (build[ 0 ] != 0);
  339. if( ret )
  340. {
  341. Cbuf_AddText (build);
  342. }
  343. Z_Free( text );
  344. Z_Free( build );
  345. return ret;
  346. }
  347. /*
  348. ==============================================================================
  349. SCRIPT COMMANDS
  350. ==============================================================================
  351. */
  352. /*
  353. -----------------------------------------------------------------------------
  354. Function: Cmd_Exec_f -Execute script file.
  355. Parameters: Nothing.
  356. Returns: Nothing.
  357. Notes: Console function, exec <filename>
  358. -----------------------------------------------------------------------------
  359. */
  360. PRIVATE void Cmd_Exec_f( void )
  361. {
  362. filehandle_t *hfile;
  363. char *f2;
  364. int len;
  365. if( Cmd_Argc () != 2 )
  366. {
  367. Com_Printf( "exec <filename> : execute a script file\n" );
  368. return;
  369. }
  370. hfile = FS_OpenFile( Cmd_Argv( 1 ), FA_FILE_IPHONE_DOC_DIR );
  371. if( ! hfile )
  372. {
  373. Com_Printf( "couldn't exec %s\n", Cmd_Argv( 1 ) );
  374. return;
  375. }
  376. len = FS_GetFileSize( hfile );
  377. Com_Printf( "execing %s\n", Cmd_Argv( 1 ) );
  378. // the file doesn't have a trailing 0, so we need to copy it off
  379. f2 = Z_Malloc( len + 1 );
  380. memcpy( f2, hfile->filedata, len );
  381. f2[ len ] = 0;
  382. printf( "%s", f2 ); // !@#
  383. Cbuf_InsertText( f2 );
  384. Z_Free( f2 );
  385. FS_CloseFile( hfile );
  386. }
  387. /*
  388. -----------------------------------------------------------------------------
  389. Function: Cmd_Echo_f -Prints the rest of the line to the console.
  390. Parameters: Nothing.
  391. Returns: Nothing.
  392. Notes:
  393. -----------------------------------------------------------------------------
  394. */
  395. PRIVATE void Cmd_Echo_f( void )
  396. {
  397. int i;
  398. for( i = 1 ; i < Cmd_Argc() ; ++i )
  399. {
  400. Com_Printf( "%s ",Cmd_Argv( i ) );
  401. }
  402. Com_Printf( "\n" );
  403. }
  404. /*
  405. -----------------------------------------------------------------------------
  406. Function: Cmd_Alias_f -Creates a new command that executes a command
  407. string (possibly ; seperated).
  408. Parameters: Nothing.
  409. Returns: Nothing.
  410. Notes:
  411. -----------------------------------------------------------------------------
  412. */
  413. PRIVATE void Cmd_Alias_f( void )
  414. {
  415. cmdalias_t *a;
  416. char cmd[ 1024 ];
  417. int i, c;
  418. char *s;
  419. W32 hashid;
  420. if( Cmd_Argc() == 1 )
  421. {
  422. Com_Printf( "Current alias commands:\n" );
  423. for( a = cmd_alias ; a ; a = a->next )
  424. {
  425. Com_Printf( "%s : %s\n", a->name, a->value );
  426. }
  427. return;
  428. }
  429. s = Cmd_Argv( 1 );
  430. if( strlen( s ) >= MAX_ALIAS_NAME )
  431. {
  432. Com_Printf( "Alias name is too long\n" );
  433. return;
  434. }
  435. hashid = my_strhash( s );
  436. // if the alias already exists, reuse it
  437. for( a = cmd_alias ; a ; a = a->next )
  438. {
  439. if( hashid == a->id )
  440. {
  441. Z_Free( a->value );
  442. break;
  443. }
  444. }
  445. if( ! a )
  446. {
  447. a = Z_Malloc( sizeof( cmdalias_t ) );
  448. a->next = cmd_alias;
  449. cmd_alias = a;
  450. }
  451. my_strlcpy( a->name, s, sizeof( a->name ) );
  452. a->id = hashid;
  453. // copy the rest of the command line
  454. cmd[ 0 ] = '\0'; // start out with a NUL-terminated string
  455. c = Cmd_Argc();
  456. for( i = 2; i < c; ++i )
  457. {
  458. my_strlcat( cmd, Cmd_Argv( i ), sizeof( cmd ) );
  459. if( i != (c - 1) )
  460. {
  461. my_strlcat( cmd, " ", sizeof( cmd ) );
  462. }
  463. }
  464. my_strlcat( cmd, "\n", sizeof( cmd ) );
  465. a->value = my_CopyString( cmd );
  466. }
  467. /*
  468. =============================================================================
  469. COMMAND EXECUTION
  470. =============================================================================
  471. */
  472. typedef struct cmd_function_s
  473. {
  474. struct cmd_function_s *next;
  475. char *name;
  476. W32 id;
  477. xcommand_t function;
  478. } cmd_function_t;
  479. PRIVATE int cmd_argc;
  480. PRIVATE char *cmd_argv[ MAX_STRING_TOKENS ];
  481. PRIVATE char *cmd_null_string = "";
  482. PRIVATE char cmd_args[ MAX_STRING_CHARS ];
  483. PRIVATE cmd_function_t *cmd_functions; // possible commands to execute
  484. /*
  485. -----------------------------------------------------------------------------
  486. Function: Cmd_Argc -How many arguments are passed in.
  487. Parameters: Nothing.
  488. Returns: How many arguments are passed in.
  489. Notes:
  490. -----------------------------------------------------------------------------
  491. */
  492. PUBLIC int Cmd_Argc( void )
  493. {
  494. return cmd_argc;
  495. }
  496. /*
  497. -----------------------------------------------------------------------------
  498. Function: Cmd_Argv -Retrieve one argument.
  499. Parameters: arg -[in] Which argument to retrieve.
  500. Returns: NULL if outside argument index, otherwise returns the argument
  501. string.
  502. Notes:
  503. -----------------------------------------------------------------------------
  504. */
  505. PUBLIC char *Cmd_Argv( int arg )
  506. {
  507. if( arg >= cmd_argc )
  508. {
  509. return cmd_null_string;
  510. }
  511. return cmd_argv[ arg ];
  512. }
  513. /*
  514. -----------------------------------------------------------------------------
  515. Function: Cmd_Args -Retrieve all arguments.
  516. Parameters: Nothing.
  517. Returns: A single string containing argv(1) to argv(argc()-1)
  518. Notes:
  519. -----------------------------------------------------------------------------
  520. */
  521. PUBLIC char *Cmd_Args( void )
  522. {
  523. return cmd_args;
  524. }
  525. /*
  526. -----------------------------------------------------------------------------
  527. Function: Cmd_MacroExpandString
  528. Parameters:
  529. Returns:
  530. Notes:
  531. -----------------------------------------------------------------------------
  532. */
  533. PRIVATE char *Cmd_MacroExpandString( char *text )
  534. {
  535. int i, j, count, len;
  536. _boolean inquote;
  537. char *scan;
  538. static char expanded[ MAX_STRING_CHARS ];
  539. char temporary[MAX_STRING_CHARS];
  540. char *token, *start;
  541. inquote = false;
  542. scan = text;
  543. len = strlen( scan );
  544. if( len >= MAX_STRING_CHARS )
  545. {
  546. Com_Printf( "Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS );
  547. return NULL;
  548. }
  549. count = 0;
  550. for( i = 0 ; i < len ; ++i )
  551. {
  552. if (scan[i] == '"')
  553. inquote ^= 1;
  554. if (inquote)
  555. continue; // don't expand inside quotes
  556. if (scan[i] != '$')
  557. continue;
  558. // scan out the complete macro
  559. start = scan+i+1;
  560. token = COM_Parse( &start );
  561. if (!start)
  562. continue;
  563. token = Cvar_VariableString (token);
  564. j = strlen(token);
  565. len += j;
  566. if (len >= MAX_STRING_CHARS)
  567. {
  568. Com_Printf ("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
  569. return NULL;
  570. }
  571. strncpy( temporary, scan, i );
  572. my_strlcpy( temporary+i, token, sizeof( temporary ) - i );
  573. my_strlcpy( temporary+i+j, start, sizeof( temporary ) - i - j );
  574. my_strlcpy( expanded, temporary, sizeof( expanded ) );
  575. scan = expanded;
  576. i--;
  577. if( ++count == 100 )
  578. {
  579. Com_Printf( "Macro expansion loop, discarded.\n" );
  580. return NULL;
  581. }
  582. }
  583. if( inquote )
  584. {
  585. Com_Printf( "Line has unmatched quote, discarded.\n" );
  586. return NULL;
  587. }
  588. return scan;
  589. }
  590. /*
  591. -----------------------------------------------------------------------------
  592. Function: Cmd_TokenizeString -Parses the given string into command line tokens.
  593. Parameters: text -[in] string to tokenize.
  594. macroExpand -[in] Expand macro, true for yes, otherwise false.
  595. Returns: Nothing
  596. Notes:
  597. $Cvars will be expanded unless they are in a quoted token
  598. -----------------------------------------------------------------------------
  599. */
  600. PUBLIC void Cmd_TokenizeString( char *text, _boolean macroExpand )
  601. {
  602. int i;
  603. char *com_token;
  604. // clear the args from the last string
  605. for( i = 0 ; i < cmd_argc ; ++i )
  606. {
  607. Z_Free( cmd_argv[ i ] );
  608. }
  609. cmd_argc = 0;
  610. cmd_args[ 0 ] = 0;
  611. // macro expand the text
  612. if( macroExpand )
  613. {
  614. text = Cmd_MacroExpandString( text );
  615. }
  616. if( ! text )
  617. {
  618. return;
  619. }
  620. while( 1 )
  621. {
  622. // skip whitespace up to a /n
  623. while( *text && *text <= ' ' && *text != '\n' )
  624. {
  625. text++;
  626. }
  627. if( *text == '\n' )
  628. { // a newline seperates commands in the buffer
  629. text++;
  630. break;
  631. }
  632. if( ! *text )
  633. {
  634. return;
  635. }
  636. // set cmd_args to everything after the first arg
  637. if( cmd_argc == 1 )
  638. {
  639. int l;
  640. my_strlcpy( cmd_args, text, sizeof( cmd_args ) - 1 );
  641. // strip off any trailing whitespace
  642. l = strlen( cmd_args ) - 1;
  643. for( ; l >= 0 ; --l )
  644. {
  645. if (cmd_args[l] <= ' ')
  646. {
  647. cmd_args[l] = 0;
  648. }
  649. else
  650. {
  651. break;
  652. }
  653. }
  654. }
  655. com_token = COM_Parse( &text );
  656. if( ! text )
  657. {
  658. return;
  659. }
  660. if( cmd_argc < MAX_STRING_TOKENS )
  661. {
  662. cmd_argv[ cmd_argc ] = Z_Malloc( strlen( com_token ) + 1 );
  663. my_strlcpy( cmd_argv[ cmd_argc ], com_token, strlen( com_token ) + 1 );
  664. cmd_argc++;
  665. }
  666. }
  667. }
  668. /*
  669. -----------------------------------------------------------------------------
  670. Function: Cmd_AddCommand -Add a command name and function to the cmd repository.
  671. Parameters:
  672. cmd_name -[in] Pointer to a NUL-terminated string that constains a
  673. command name.
  674. function -[in] Function to associate with cmd_name.
  675. Returns: Nothing.
  676. Notes:
  677. -----------------------------------------------------------------------------
  678. */
  679. PUBLIC void Cmd_AddCommand( char *cmd_name, xcommand_t function )
  680. {
  681. cmd_function_t *cmd;
  682. W32 hashid;
  683. // fail if the command is a variable name
  684. if( Cvar_VariableString( cmd_name )[ 0 ] )
  685. {
  686. Com_Printf( "Cmd_AddCommand: \"%s\" already defined as a var\n", cmd_name );
  687. return;
  688. }
  689. hashid = my_strhash( cmd_name );
  690. // fail if the command already exists
  691. for( cmd = cmd_functions ; cmd ; cmd = cmd->next )
  692. {
  693. if( hashid == cmd->id )
  694. {
  695. Com_Printf( "Cmd_AddCommand: \"%s\" already defined\n", cmd_name );
  696. return;
  697. }
  698. }
  699. cmd = Z_Malloc( sizeof( cmd_function_t ) );
  700. cmd->name = cmd_name;
  701. cmd->id = hashid;
  702. cmd->function = function;
  703. cmd->next = cmd_functions;
  704. cmd_functions = cmd;
  705. }
  706. /*
  707. -----------------------------------------------------------------------------
  708. Function: Cmd_RemoveCommand -Remove command.
  709. Parameters: cmd_name -[in] name of command to remove.
  710. Returns: Nothing.
  711. Notes:
  712. -----------------------------------------------------------------------------
  713. */
  714. PUBLIC void Cmd_RemoveCommand( char *cmd_name )
  715. {
  716. cmd_function_t *cmd, **back;
  717. W32 hashid;
  718. hashid = my_strhash( cmd_name );
  719. back = &cmd_functions;
  720. while( 1 )
  721. {
  722. cmd = *back;
  723. if( ! cmd )
  724. {
  725. Com_DPrintf( "Cmd_RemoveCommand: %s was not added\n", cmd_name );
  726. return;
  727. }
  728. if( hashid == cmd->id )
  729. {
  730. *back = cmd->next;
  731. Z_Free( cmd );
  732. return;
  733. }
  734. back = &cmd->next;
  735. }
  736. }
  737. /*
  738. -----------------------------------------------------------------------------
  739. Function: Cmd_Exists -Check to see if command already exists.
  740. Parameters: cmd_name -[in] name of command to check.
  741. Returns: true if the command already exists, otherwise false.
  742. Notes:
  743. -----------------------------------------------------------------------------
  744. */
  745. PUBLIC _boolean Cmd_Exists( char *cmd_name )
  746. {
  747. cmd_function_t *cmd;
  748. W32 hashid = my_strhash( cmd_name );
  749. for( cmd = cmd_functions ; cmd ; cmd = cmd->next )
  750. {
  751. if( hashid == cmd->id )
  752. {
  753. return true;
  754. }
  755. }
  756. return false;
  757. }
  758. /*
  759. -----------------------------------------------------------------------------
  760. Function: Cmd_CompleteCommand -Complete partial command on console
  761. command-line.
  762. Parameters: partial -[in] Partial name of command.
  763. Returns: NULL if no command exists, otherwise returns the complete name of
  764. command.
  765. Notes:
  766. -----------------------------------------------------------------------------
  767. */
  768. PUBLIC char *Cmd_CompleteCommand( char *partial )
  769. {
  770. cmd_function_t *cmd;
  771. int len;
  772. cmdalias_t *a;
  773. W32 hashid;
  774. len = strlen( partial );
  775. if( ! len )
  776. {
  777. return NULL;
  778. }
  779. //
  780. // Check for exact match.
  781. //
  782. hashid = my_strhash( partial );
  783. for( cmd = cmd_functions ; cmd ; cmd = cmd->next )
  784. {
  785. if( hashid == cmd->id )
  786. {
  787. return cmd->name;
  788. }
  789. }
  790. for( a = cmd_alias ; a ; a = a->next )
  791. {
  792. if( hashid == a->id )
  793. {
  794. return a->name;
  795. }
  796. }
  797. //
  798. // Check for partial match.
  799. //
  800. for( cmd = cmd_functions ; cmd ; cmd = cmd->next )
  801. {
  802. if( ! strncmp( partial, cmd->name, len ) )
  803. {
  804. return cmd->name;
  805. }
  806. }
  807. for( a = cmd_alias ; a ; a = a->next )
  808. {
  809. if( ! strncmp( partial, a->name, len ) )
  810. {
  811. return a->name;
  812. }
  813. }
  814. return NULL;
  815. }
  816. /*
  817. -----------------------------------------------------------------------------
  818. Function: Cmd_ExecuteString -Execute command string.
  819. Parameters: text -[in] text string to execute.
  820. Returns: Nothing.
  821. Notes:
  822. A complete command line has been parsed, so try to execute it
  823. FIXME: lookupnoadd the token to speed search?
  824. -----------------------------------------------------------------------------
  825. */
  826. PUBLIC void Cmd_ExecuteString( char *text )
  827. {
  828. cmd_function_t *cmd;
  829. cmdalias_t *a;
  830. W32 hashid;
  831. Cmd_TokenizeString( text, true );
  832. // execute the command line
  833. if( ! Cmd_Argc() )
  834. {
  835. return; // no tokens
  836. }
  837. hashid = my_strhash( cmd_argv[ 0 ] );
  838. // check functions
  839. for( cmd = cmd_functions ; cmd ; cmd = cmd->next )
  840. {
  841. if( hashid == cmd->id )
  842. {
  843. if( ! cmd->function )
  844. { // forward to server command
  845. Cmd_ExecuteString( va( "cmd %s", text ) );
  846. }
  847. else
  848. {
  849. cmd->function();
  850. }
  851. return;
  852. }
  853. }
  854. // check alias
  855. for( a = cmd_alias ; a ; a = a->next )
  856. {
  857. if( ! my_stricmp( cmd_argv[ 0 ], a->name ) )
  858. {
  859. if( ++alias_count == ALIAS_LOOP_COUNT )
  860. {
  861. Com_Printf( "ALIAS_LOOP_COUNT\n" );
  862. return;
  863. }
  864. Cbuf_InsertText( a->value );
  865. return;
  866. }
  867. }
  868. // check cvars
  869. if( Cvar_Command() )
  870. {
  871. return;
  872. }
  873. // send it as a server command if we are connected
  874. // Cmd_ForwardToServer();
  875. }
  876. /*
  877. -----------------------------------------------------------------------------
  878. Function: Cmd_List_f -Callback function that list commands.
  879. Parameters: Nothing.
  880. Returns: Nothing.
  881. Notes: List commands and total number of commands.
  882. -----------------------------------------------------------------------------
  883. */
  884. PRIVATE void Cmd_List_f( void )
  885. {
  886. cmd_function_t *cmd;
  887. int i = 0;
  888. for( cmd = cmd_functions; cmd; cmd = cmd->next, ++i )
  889. {
  890. Com_Printf( "%s\n", cmd->name );
  891. }
  892. Com_Printf( "%i commands\n", i );
  893. }
  894. /*
  895. -----------------------------------------------------------------------------
  896. Function: Cmd_Init -Initialize the command buffer.
  897. Parameters: Nothing.
  898. Returns: Nothing.
  899. Notes:
  900. -----------------------------------------------------------------------------
  901. */
  902. PUBLIC void Cmd_Init( void )
  903. {
  904. Cbuf_Init();
  905. //
  906. // register our commands
  907. //
  908. Cmd_AddCommand( "listCmds", Cmd_List_f );
  909. Cmd_AddCommand( "exec", Cmd_Exec_f );
  910. Cmd_AddCommand( "echo", Cmd_Echo_f );
  911. Cmd_AddCommand( "alias", Cmd_Alias_f);
  912. Cmd_AddCommand( "wait", Cmd_Wait_f );
  913. }