cmd.c 15 KB

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