UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cmd.cpp
Go to the documentation of this file.
1 
14 /*
15 Copyright (C) 1997-2001 Id Software, Inc.
16 
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License
19 as published by the Free Software Foundation; either version 2
20 of the License, or (at your option) any later version.
21 
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 
26 See the GNU General Public License for more details.
27 
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 
32 */
33 
34 #include "cmd.h"
35 #include "common.h"
36 #include "msg.h"
37 #include "../shared/parse.h"
38 
39 void Cmd_ForwardToServer(void);
40 #define ALIAS_HASH_SIZE 32
41 
42 #define MAX_ALIAS_NAME 32
43 
44 typedef struct cmd_alias_s {
46  char* value;
47  bool archive;
49  struct cmd_alias_s* next;
50 } cmd_alias_t;
51 
52 typedef std::vector<CmdListenerPtr> CmdListeners;
53 
57 static bool cmdWait;
58 static bool cmdClosed;
59 
60 #define ALIAS_LOOP_COUNT 16
61 static int alias_count; /* for detecting runaway loops */
62 
63 
68 static void Cmd_Open_f (void)
69 {
70  Com_DPrintf(DEBUG_COMMANDS, "Cmd_Close_f: command buffer opened again\n");
71  cmdClosed = false;
72 }
73 
79 static void Cmd_Close_f (void)
80 {
81  Com_DPrintf(DEBUG_COMMANDS, "Cmd_Close_f: command buffer closed\n");
82  cmdClosed = true;
83 }
84 
90 static void Cmd_Wait_f (void)
91 {
92  cmdWait = true;
93 }
94 
95 /*
96 =============================================================================
97 COMMAND BUFFER
98 =============================================================================
99 */
100 
101 #define CMD_BUFFER_SIZE 8192
105 
109 void Cbuf_Init (void)
110 {
111  SZ_Init(&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
112 }
113 
117 void Cbuf_Shutdown (void)
118 {
119  SZ_Init(&cmd_text, nullptr, 0);
120 }
121 
126 void Cbuf_AddText (const char* format, ...)
127 {
128  va_list argptr;
129  static char text[CMD_BUFFER_SIZE];
130  va_start(argptr, format);
131  Q_vsnprintf(text, sizeof(text), format, argptr);
132  va_end(argptr);
133 
134  if (cmdClosed) {
135  if (!Q_strstart(text, "cmdopen")) {
136  Com_DPrintf(DEBUG_COMMANDS, "Cbuf_AddText: currently closed\n");
137  return;
138  }
139  }
140 
141  const int len = strlen(text);
142 
143  if (cmd_text.cursize + len >= cmd_text.maxsize) {
144  Com_Printf("Cbuf_AddText: overflow (%i) (%s)\n", cmd_text.maxsize, text);
145  Com_Printf("buffer content: %s\n", cmd_text_buf);
146  return;
147  }
148  SZ_Write(&cmd_text, text, len);
149 }
150 
151 
157 void Cbuf_InsertText (const char* text)
158 {
159  if (Q_strnull(text))
160  return;
161 
162  /* copy off any commands still remaining in the exec buffer */
163  char* temp;
164  const int templen = cmd_text.cursize;
165 
166  if (templen) {
167  temp = Mem_AllocTypeN(char, templen);
168  memcpy(temp, cmd_text.data, templen);
169  SZ_Clear(&cmd_text);
170  } else {
171  temp = nullptr; /* shut up compiler */
172  }
173 
174  /* add the entire text of the file */
175  Cbuf_AddText("%s\n", text);
176 
177  /* add the copied off data */
178  if (templen) {
179  SZ_Write(&cmd_text, temp, templen);
180  Mem_Free(temp);
181  }
182 }
183 
184 
191 void Cbuf_CopyToDefer (void)
192 {
193  memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
194  defer_text_buf[cmd_text.cursize] = 0;
195  cmd_text.cursize = 0;
196 }
197 
202 {
204  defer_text_buf[0] = 0;
205 }
206 
214 void Cbuf_Execute (void)
215 {
216  /* don't allow infinite alias loops */
217  alias_count = 0;
218 
219  while (cmd_text.cursize) {
220  unsigned int i;
221  char line[1024];
222 
223  /* find a \n or ; line break */
224  char* text = (char*) cmd_text.data;
225  int quotes = 0;
226 
227  for (i = 0; i < cmd_text.cursize; i++) {
228  if (text[i] == '"')
229  quotes++;
230  /* don't break if inside a quoted string */
231  if (!(quotes & 1) && text[i] == ';')
232  break;
233  if (text[i] == '\n')
234  break;
235  }
236 
237  if (i > sizeof(line) - 1)
238  i = sizeof(line) - 1;
239 
240  memcpy(line, text, i);
241  line[i] = 0;
242 
243  /* delete the text from the command buffer and move remaining commands down
244  * this is necessary because commands (exec, alias) can insert data at the
245  * beginning of the text buffer */
246  if (i == cmd_text.cursize)
247  cmd_text.cursize = 0;
248  else {
249  i++;
250  cmd_text.cursize -= i;
251  memmove(text, text + i, cmd_text.cursize);
252  }
253 
254  /* execute the command line */
255  Cmd_ExecuteString("%s", line);
256 
257  if (cmdWait) {
258  /* skip out while text still remains in buffer, leaving it
259  * for next frame */
260  cmdWait = false;
261  break;
262  }
263  }
264 }
265 
266 
275 void Cbuf_AddEarlyCommands (bool clear)
276 {
277  const int argc = Com_Argc();
278  for (int i = 1; i < argc; i++) {
279  const char* s = Com_Argv(i);
280  if (!Q_streq(s, "+set"))
281  continue;
282  Cbuf_AddText("set %s %s\n", Com_Argv(i + 1), Com_Argv(i + 2));
283  if (clear) {
284  Com_ClearArgv(i);
285  Com_ClearArgv(i + 1);
286  Com_ClearArgv(i + 2);
287  }
288  i += 2;
289  }
290 }
291 
299 {
300  /* build the combined string to parse from */
301  int s = 0;
302  const int argc = Com_Argc();
303  for (int i = 1; i < argc; i++) {
304  s += strlen(Com_Argv(i)) + 1;
305  }
306  if (!s)
307  return false;
308 
309  char* text = Mem_AllocTypeN(char, s + 1);
310  for (int i = 1; i < argc; i++) {
311  Q_strcat(text, s, "%s", Com_Argv(i));
312  if (i != argc - 1)
313  Q_strcat(text, s, " ");
314  }
315 
316  /* pull out the commands */
317  char* build = Mem_AllocTypeN(char, s + 1);
318 
319  for (int i = 0; i < s - 1; i++) {
320  if (text[i] != '+')
321  continue;
322  i++;
323 
324  int j;
325  for (j = i; text[j] != '+' && text[j] != '-' && text[j] != '\0'; j++) {}
326 
327  const char c = text[j];
328  text[j] = '\0';
329 
330  Q_strcat(build, s, "%s\n", text + i);
331  text[j] = c;
332  i = j - 1;
333  }
334 
335  const bool ret = build[0] != '\0';
336  if (ret)
337  Cbuf_AddText("%s", build);
338 
339  Mem_Free(text);
340  Mem_Free(build);
341 
342  return ret;
343 }
344 
345 
346 /*
347 ==============================================================================
348 SCRIPT COMMANDS
349 ==============================================================================
350 */
351 
352 static void Cmd_Exec_f (void)
353 {
354  if (Cmd_Argc() != 2) {
355  Com_Printf("Usage: %s <filename> : execute a script file\n", Cmd_Argv(0));
356  return;
357  }
358 
359  byte* f;
360  const int len = FS_LoadFile(Cmd_Argv(1), &f);
361  if (!f) {
362  Com_Printf("couldn't execute %s\n", Cmd_Argv(1));
363  return;
364  }
365  Com_Printf("executing %s\n", Cmd_Argv(1));
366 
367  /* the file doesn't have a trailing 0, so we need to copy it off */
368  char* f2 = Mem_AllocTypeN(char, len + 1);
369  memcpy(f2, f, len);
370  /* make really sure that there is a newline */
371  f2[len] = 0;
372 
373  Cbuf_InsertText(f2);
374 
375  Mem_Free(f2);
376  FS_FreeFile(f);
377 }
378 
379 
383 static void Cmd_Echo_f (void)
384 {
385  for (int i = 1; i < Cmd_Argc(); i++)
386  Com_Printf("%s ", Cmd_Argv(i));
387  Com_Printf("\n");
388 }
389 
393 static void Cmd_Alias_f (void)
394 {
395  cmd_alias_t* a;
396 
397  if (Cmd_Argc() == 1) {
398  Com_Printf("Current alias commands:\n");
399  for (a = cmd_alias; a; a = a->next)
400  Com_Printf("%s : %s\n", a->name, a->value);
401  return;
402  }
403 
404  const char* s = Cmd_Argv(1);
405  const size_t len = strlen(s);
406  if (len == 0)
407  return;
408 
409  if (len >= MAX_ALIAS_NAME) {
410  Com_Printf("Alias name is too long\n");
411  return;
412  }
413 
414  /* if the alias already exists, reuse it */
415  const unsigned int hash = Com_HashKey(s, ALIAS_HASH_SIZE);
416  for (a = cmd_alias_hash[hash]; a; a = a->hash_next) {
417  if (Q_streq(s, a->name)) {
418  Mem_Free(a->value);
419  break;
420  }
421  }
422 
423  if (!a) {
425  a->next = cmd_alias;
426  /* cmd_alias_hash should be null on the first run */
427  a->hash_next = cmd_alias_hash[hash];
428  cmd_alias_hash[hash] = a;
429  cmd_alias = a;
430  }
431  Q_strncpyz(a->name, s, sizeof(a->name));
432 
433  /* copy the rest of the command line */
434  char cmd[MAX_STRING_CHARS];
435  cmd[0] = 0; /* start out with a null string */
436  const int c = Cmd_Argc();
437  for (int i = 2; i < c; i++) {
438  Q_strcat(cmd, sizeof(cmd), "%s", Cmd_Argv(i));
439  if (i != (c - 1))
440  Q_strcat(cmd, sizeof(cmd), " ");
441  }
442 
443  if (Q_streq(Cmd_Argv(0), "aliasa"))
444  a->archive = true;
445 
446  a->value = Mem_PoolStrDup(cmd, com_aliasSysPool, 0);
447 }
448 
455 {
456  for (cmd_alias_t* a = cmd_alias; a; a = a->next)
457  if (a->archive) {
458  FS_Printf(f, "aliasa %s \"", a->name);
459  for (int i = 0; i < strlen(a->value); i++) {
460  if (a->value[i] == '"')
461  FS_Printf(f, "\\\"");
462  else
463  FS_Printf(f, "%c", a->value[i]);
464  }
465  FS_Printf(f, "\"\n");
466  }
467 }
468 
469 /*
470 =============================================================================
471 COMMAND EXECUTION
472 =============================================================================
473 */
474 
475 #define CMD_HASH_SIZE 32
476 
477 typedef struct cmd_function_s {
480  const char* name;
481  const char* description;
482  xcommand_t function;
483  int (*completeParam) (const char* partial, const char** match);
484  void* userdata;
485 
486  inline const char* getName() const {
487  return name;
488  }
490 
491 static int cmd_argc;
494 static void* cmd_userdata;
495 
496 static cmd_function_t* cmd_functions; /* possible commands to execute */
498 
505 int Cmd_Argc (void)
506 {
507  return cmd_argc;
508 }
509 
516 const char* Cmd_Argv (int arg)
517 {
518  if (arg >= cmd_argc)
519  return "";
520  return cmd_argv[arg];
521 }
522 
526 const char* Cmd_Args (void)
527 {
528  return cmd_args;
529 }
530 
534 void* Cmd_Userdata (void)
535 {
536  return cmd_userdata;
537 }
538 
543 void Cmd_BufClear (void)
544 {
545  /* clear the args from the last string */
546  for (int i = 0; i < cmd_argc; i++) {
547  Mem_Free(cmd_argv[i]);
548  cmd_argv[i] = nullptr;
549  }
550 
551  cmd_argc = 0;
552  cmd_args[0] = 0;
553  cmd_userdata = nullptr;
554 }
555 
565 void Cmd_TokenizeString (const char* text, bool macroExpand, bool replaceWhitespaces)
566 {
567  Cmd_BufClear();
568 
569  /* macro expand the text */
570  if (macroExpand) {
571  const char* expanded = Com_MacroExpandString(text);
572  if (expanded)
573  text = expanded;
574  }
575 
576  while (1) {
577  /* skip whitespace up to a newline */
578  while (*text && *text <= ' ' && *text != '\n') {
579  text++;
580  }
581 
582  if (*text == '\n') { /* a newline seperates commands in the buffer */
583  text++;
584  break;
585  }
586 
587  if (!*text)
588  return;
589 
590  /* set cmd_args to everything after the first arg */
591  if (cmd_argc == 1) {
592  Q_strncpyz(cmd_args, text, sizeof(cmd_args));
594  }
595 
596  const char* com_token = Com_Parse(&text, nullptr, 0, replaceWhitespaces);
597  if (!text)
598  return;
599 
600  if (cmd_argc < MAX_STRING_TOKENS) {
601  /* check first char of string if it is a variable */
602  if (com_token[0] == '*') {
603  com_token++;
604  com_token = Cvar_GetString(com_token);
605  }
606  assert(!cmd_argv[cmd_argc]);
608  cmd_argc++;
609  }
610  }
611 }
612 
613 static cmd_function_t* Cmd_TableFind (const char* cmdName)
614 {
615  const unsigned int hash = Com_HashKey(cmdName, CMD_HASH_SIZE);
616  for (cmd_function_t* cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
617  if (Q_streq(cmdName, cmd->getName()))
618  return cmd;
619  }
620  return nullptr;
621 }
622 
629 const char* Cmd_GetCommandDesc (const char* cmdName)
630 {
631  char searchName[MAX_VAR];
632 
633  /* remove parameters */
634  Q_strncpyz(searchName, cmdName, sizeof(searchName));
635  char* sep = strstr(searchName, " ");
636  if (sep)
637  *sep = '\0';
638 
639  const cmd_function_t* cmd = Cmd_TableFind(searchName);
640  if (cmd) {
641  if (cmd->description)
642  return cmd->description;
643  return "";
644  }
645  return "";
646 }
647 
648 bool Cmd_GenericCompleteFunction(char const* candidate, char const* partial, char const** match)
649 {
650  static char matchString[MAX_QPATH];
651 
652  if (!Q_strstart(candidate, partial))
653  return false;
654 
655  if (!*match) {
656  /* First match. */
657  Q_strncpyz(matchString, candidate, sizeof(matchString));
658  *match = matchString;
659  } else {
660  /* Subsequent match, determine common prefix with previous match(es). */
661  char* dst = matchString;
662  char const* src = candidate;
663  while (*dst == *src) {
664  ++dst;
665  ++src;
666  }
667  *dst = '\0';
668  }
669 
670  return true;
671 }
672 
679 void Cmd_AddParamCompleteFunction (const char* cmdName, int (*function)(const char* partial, const char** match))
680 {
681  if (!cmdName || !cmdName[0])
682  return;
683 
684  cmd_function_t* cmd = Cmd_TableFind(cmdName);
685  if (cmd) {
686  cmd->completeParam = function;
687  return;
688  }
689 }
690 
700 void* Cmd_GetUserdata (const char* cmdName)
701 {
702  if (!cmdName || !cmdName[0]) {
703  Com_Printf("Cmd_GetUserdata: Invalide parameter\n");
704  return nullptr;
705  }
706 
707  const cmd_function_t* cmd = Cmd_TableFind(cmdName);
708  if (cmd) {
709  return cmd->userdata;
710  }
711 
712  Com_Printf("Cmd_GetUserdata: '%s' not found\n", cmdName);
713  return nullptr;
714 }
715 
724 void Cmd_AddUserdata (const char* cmdName, void* userdata)
725 {
726  if (!cmdName || !cmdName[0])
727  return;
728 
729  cmd_function_t* cmd = Cmd_TableFind(cmdName);
730  if (cmd) {
731  cmd->userdata = userdata;
732  return;
733  }
734 }
735 
744 void Cmd_AddCommand (const char* cmdName, xcommand_t function, const char* desc)
745 {
746  if (!Q_strvalid(cmdName))
747  return;
748 
749  /* fail if the command is a variable name */
750  if (Cvar_GetString(cmdName)[0]) {
751  Com_Printf("Cmd_AddCommand: %s already defined as a var\n", cmdName);
752  return;
753  }
754 
755  /* fail if the command already exists */
756  const cmd_function_t* const cmdOld = Cmd_TableFind(cmdName);
757  if (cmdOld) {
758  Com_DPrintf(DEBUG_COMMANDS, "Cmd_AddCommand: %s already defined\n", cmdName);
759  return;
760  }
761 
762  /* create the new command entry ... */
764  cmd->name = cmdName;
765  cmd->description = desc;
766  cmd->function = function;
767  cmd->completeParam = nullptr;
768 
769  /* ... add it to the hashtable */
770  const unsigned int hash = Com_HashKey(cmdName, CMD_HASH_SIZE);
771  HASH_Add(cmd_functions_hash, cmd, hash);
772  /* ... and to the cmd table */
773  cmd->next = cmd_functions;
774  cmd_functions = cmd;
775 
776  for (CmdListeners::const_iterator i = cmdListeners.begin(); i != cmdListeners.end(); ++i) {
777  (*i)->onAdd(cmdName);
778  }
779 }
780 
786 void Cmd_RemoveCommand (const char* cmdName)
787 {
788  const unsigned int hash = Com_HashKey(cmdName, CMD_HASH_SIZE);
789  cmd_function_t **back = &cmd_functions_hash[hash];
790 
791  while (1) {
792  cmd_function_t* cmd = *back;
793  if (!cmd) {
794  Com_Printf("Cmd_RemoveCommand: %s not added\n", cmdName);
795  return;
796  }
797  if (Q_streq(cmdName, cmd->getName())) {
798  *back = cmd->hash_next;
799  break;
800  }
801  back = &cmd->hash_next;
802  }
803 
804  back = &cmd_functions;
805  while (1) {
806  cmd_function_t* cmd = *back;
807  if (!cmd) {
808  Com_Printf("Cmd_RemoveCommand: %s not added\n", cmdName);
809  return;
810  }
811  if (Q_streq(cmdName, cmd->getName())) {
812  *back = cmd->next;
813  Mem_Free(cmd);
814  for (CmdListeners::const_iterator i = cmdListeners.begin(); i != cmdListeners.end(); ++i) {
815  (*i)->onRemove(cmdName);
816  }
817  return;
818  }
819  back = &cmd->next;
820  }
821 }
822 
826 void Cmd_TableCheck (void)
827 {
828 #ifdef PARANOID
829  int cmdCount = 0;
830  for (cmd_function_t* cmd = cmd_functions; cmd; cmd = cmd->next) {
831  cmdCount++;
832  if (Q_streq("hugo", cmd->getName())) {
833  Com_Printf("Cmd_TableCheck: found bad entry\n");
834  return;
835  }
836  }
837  int hashCount = 0;
838  for (int i = 0; i < CMD_HASH_SIZE; i++) {
839  for (cmd_function_t* cmd = cmd_functions_hash[i]; cmd; cmd = cmd->hash_next) {
840  hashCount++;
841  if (Q_streq("hugo", cmd->getName())) {
842  Com_Printf("Cmd_TableCheck: found bad hash entry\n");
843  return;
844  }
845  }
846  }
847  /* This causes a <path/to/ufo>/(null)/ufoconsole.log to be created just to log this line
848  * file system shutdown has already run */
849  Com_Printf("cmdCount: %i hashCount: %i\n", cmdCount, hashCount);
850 #endif
851 }
852 
853 void Cmd_TableAddList (const cmdList_t* cmdList)
854 {
855  for (const cmdList_t* cmd = cmdList; cmd->name; cmd++)
856  Cmd_AddCommand(cmd->name, cmd->function, cmd->description);
857 }
858 
859 void Cmd_TableRemoveList (const cmdList_t* cmdList)
860 {
861  for (const cmdList_t* cmd = cmdList; cmd->name; cmd++)
862  Cmd_RemoveCommand(cmd->name);
863 }
864 
870 {
871  cmdListeners.push_back(listener);
872 }
873 
879 {
880  cmdListeners.erase(std::remove(cmdListeners.begin(), cmdListeners.end(), listener), cmdListeners.end());
881 }
882 
887 bool Cmd_Exists (const char* cmdName)
888 {
889  const cmd_function_t* cmd = Cmd_TableFind(cmdName);
890  if (cmd)
891  return true;
892  return false;
893 }
894 
903 int Cmd_CompleteCommandParameters (const char* command, const char* partial, const char** match)
904 {
905  /* check for partial matches in commands */
906  const unsigned int hash = Com_HashKey(command, CMD_HASH_SIZE);
907  for (const cmd_function_t* cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
908  if (!Q_strcasecmp(command, cmd->getName())) {
909  if (!cmd->completeParam)
910  return 0;
911  return cmd->completeParam(partial, match);
912  }
913  }
914  return 0;
915 }
916 
924 int Cmd_CompleteCommand (const char* partial, const char** match)
925 {
926  if (partial[0] == '\0')
927  return 0;
928 
929  int n = 0;
930 
931  /* check for partial matches in commands */
932  for (cmd_function_t const* cmd = cmd_functions; cmd; cmd = cmd->next) {
933  if (Cmd_GenericCompleteFunction(cmd->getName(), partial, match)) {
934  Com_Printf("[cmd] %s\n", cmd->getName());
935  if (cmd->description)
936  Com_Printf(S_COLOR_GREEN " %s\n", cmd->description);
937  ++n;
938  }
939  }
940 
941  /* and then aliases */
942  for (cmd_alias_t const* a = cmd_alias; a; a = a->next) {
943  if (Cmd_GenericCompleteFunction(a->name, partial, match)) {
944  Com_Printf("[ali] %s\n", a->name);
945  ++n;
946  }
947  }
948 
949  return n;
950 }
951 
952 void Cmd_vExecuteString (const char* fmt, va_list ap)
953 {
954  char text[1024];
955  Q_vsnprintf(text, sizeof(text), fmt, ap);
956 
957  Com_DPrintf(DEBUG_COMMANDS, "ExecuteString: '%s'\n", text);
958 
959  Cmd_TokenizeString(text, true);
960 
961  /* execute the command line */
962  if (!Cmd_Argc())
963  /* no tokens */
964  return;
965 
966  const char* str = Cmd_Argv(0);
967 
968  /* check functions */
969  unsigned int hash = Com_HashKey(str, CMD_HASH_SIZE);
970  for (const cmd_function_t* cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
971  if (!Q_strcasecmp(str, cmd->getName())) {
972  if (!cmd->function) { /* forward to server command */
973  Cmd_ExecuteString("cmd %s", text);
974  } else {
975  cmd_userdata = cmd->userdata;
976  cmd->function();
977  }
978  return;
979  }
980  }
981 
982  /* check alias */
983  hash = Com_HashKey(str, ALIAS_HASH_SIZE);
984  for (const cmd_alias_t* a = cmd_alias_hash[hash]; a; a = a->hash_next) {
985  if (!Q_strcasecmp(str, a->name)) {
986  if (++alias_count == ALIAS_LOOP_COUNT) {
987  Com_Printf("ALIAS_LOOP_COUNT\n");
988  return;
989  }
990  Cbuf_InsertText(a->value);
991  return;
992  }
993  }
994 
995  /* check cvars */
996  if (Cvar_Command())
997  return;
998 
999  /* send it as a server command if we are connected */
1001 }
1002 
1007 void Cmd_ExecuteString (const char* text, ...)
1008 {
1009  va_list ap;
1010 
1011  va_start(ap, text);
1012  Cmd_vExecuteString(text, ap);
1013  va_end(ap);
1014 }
1015 
1019 static void Cmd_Help_f (void)
1020 {
1021  Com_Printf(S_COLOR_GREEN " Use cmdlist and cvarlist. Both accept a partial name.\n");
1022  Com_Printf(S_COLOR_GREEN " Note that both lists can vary depending on where in the game you are.\n");
1023 }
1024 
1028 static void Cmd_List_f (void)
1029 {
1030  int i = 0, j = 0, len = 0;
1031  const char* token = nullptr;
1032 
1033  const int c = Cmd_Argc();
1034 
1035  if (c == 2) {
1036  token = Cmd_Argv(1);
1037  len = strlen(token);
1038  }
1039 
1040  for (const cmd_function_t* cmd = cmd_functions; cmd; cmd = cmd->next, i++) {
1041  if (c == 2 && strncmp(cmd->getName(), token, len)) {
1042  i--;
1043  continue;
1044  }
1045  Com_Printf("[cmd] %s\n", cmd->getName());
1046  if (cmd->description)
1047  Com_Printf(S_COLOR_GREEN " %s\n", cmd->description);
1048  }
1049  /* check alias */
1050  for (const cmd_alias_t* alias = cmd_alias; alias; alias = alias->next, j++) {
1051  if (c == 2 && strncmp(alias->name, token, len)) {
1052  j--;
1053  continue;
1054  }
1055  Com_Printf("[ali] %s\n", alias->name);
1056  }
1057  Com_Printf("%i commands\n", i);
1058  Com_Printf("%i macros\n", j);
1059 }
1060 
1061 
1066 static int Cmd_CompleteExecCommand (const char* partial, const char** match)
1067 {
1068  int n = 0;
1069  while (char const* filename = FS_NextFileFromFileList("*.cfg")) {
1070  if (Cmd_GenericCompleteFunction(filename, partial, match)) {
1071  Com_Printf("%s\n", filename);
1072  ++n;
1073  }
1074  }
1075  FS_NextFileFromFileList(nullptr);
1076 
1077  return n;
1078 }
1079 
1083 void Cmd_Dummy_f (void)
1084 {
1085 }
1086 
1087 #ifdef DEBUG
1088 
1093 static void Cmd_Test_f (void)
1094 {
1095  for (cmd_function_t* cmd = cmd_functions; cmd; cmd = cmd->next) {
1096  if (!Q_streq(cmd->getName(), "quit"))
1097  Cmd_ExecuteString("%s", cmd->getName());
1098  }
1099 }
1100 
1101 void Cmd_PrintDebugCommands (void)
1102 {
1103  const char* otherCommands[] = {"mem_stats", "cl_configstrings", "cl_userinfo", "devmap"};
1104  int num = lengthof(otherCommands);
1105 
1106  Com_Printf("Debug commands:\n");
1107  for (const cmd_function_t* cmd = cmd_functions; cmd; cmd = cmd->next) {
1108  if (Q_strstart(cmd->getName(), "debug_"))
1109  Com_Printf(" * %s\n %s\n", cmd->getName(), cmd->description);
1110  }
1111 
1112  Com_Printf("Other useful commands:\n");
1113  while (num) {
1114  const char* desc = Cmd_GetCommandDesc(otherCommands[num - 1]);
1115  Com_Printf(" * %s\n %s\n", otherCommands[num - 1], desc);
1116  num--;
1117  }
1118  Com_Printf(" * sv debug_showall\n"
1119  " make everything visible to everyone\n"
1120  " * sv debug_actorinvlist\n"
1121  " Show the whole inv of all actors on the server console\n"
1122  );
1123  Com_Printf("\n");
1124 }
1125 #endif
1126 
1127 void Cmd_Init (void)
1128 {
1129  /* register our commands */
1130  Cmd_AddCommand("help", Cmd_Help_f, "Display some help about cmd and cvar usage");
1131  Cmd_AddCommand("cmdlist", Cmd_List_f, "List all commands to game console");
1132  Cmd_AddCommand("exec", Cmd_Exec_f, "Execute a script file");
1134  Cmd_AddCommand("echo", Cmd_Echo_f, "Print to game console");
1135  Cmd_AddCommand("wait", Cmd_Wait_f);
1136  Cmd_AddCommand("alias", Cmd_Alias_f, "Creates a new command that executes a command string");
1137  Cmd_AddCommand("aliasa", Cmd_Alias_f, "Creates a new, persistent command that executes a command string");
1138  Cmd_AddCommand("cmdclose", Cmd_Close_f, "Close the command buffer");
1139  Cmd_AddCommand("cmdopen", Cmd_Open_f, "Open the command buffer again");
1140 #ifdef DEBUG
1141  Cmd_AddCommand("debug_cmdtest", Cmd_Test_f, "Calls every command in the current list");
1142 #endif
1143 }
1144 
1145 void Cmd_Shutdown (void)
1146 {
1147  OBJZERO(cmd_functions_hash);
1148  cmd_functions = nullptr;
1149 
1150  OBJZERO(cmd_alias_hash);
1151  cmd_alias = nullptr;
1152  alias_count = 0;
1153 
1154  OBJZERO(cmd_argv);
1155  cmd_argc = 0;
1156 
1157  cmdWait = false;
1158  cmdClosed = false;
1159 
1161 }
void Cmd_UnRegisterCmdListener(CmdListenerPtr listener)
Unregisters a command listener.
Definition: cmd.cpp:878
void Cbuf_InsertText(const char *text)
Adds command text immediately after the current command.
Definition: cmd.cpp:157
bool Q_strnull(const char *string)
Definition: shared.h:138
void Cmd_vExecuteString(const char *fmt, va_list ap)
Definition: cmd.cpp:952
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
static void Cmd_Wait_f(void)
Causes execution of the remainder of the command buffer to be delayed until next frame. This allows commands like: bind g "impulse 5; +attack; wait; -attack; impulse 2".
Definition: cmd.cpp:90
void Cmd_Init(void)
Definition: cmd.cpp:1127
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
const char * FS_NextFileFromFileList(const char *files)
Returns the next file that is found in the virtual filesystem identified by the given file pattern...
Definition: files.cpp:1079
static void Cmd_Alias_f(void)
Creates a new command that executes a command string (possibly ; separated)
Definition: cmd.cpp:393
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition: shared.cpp:535
const char * Com_Argv(int arg)
Returns an argument of script commandline.
Definition: common.cpp:568
int Cmd_CompleteCommand(const char *partial, const char **match)
Unix like tab completion for console commands.
Definition: cmd.cpp:924
void Cmd_RemoveCommand(const char *cmdName)
Removes a command from script interface.
Definition: cmd.cpp:786
static int alias_count
Definition: cmd.cpp:61
static void Cmd_Help_f(void)
Display some help about cmd and cvar usage.
Definition: cmd.cpp:1019
char * value
Definition: cmd.cpp:46
struct cmd_alias_s * hash_next
Definition: cmd.cpp:48
static byte cmd_text_buf[CMD_BUFFER_SIZE]
Definition: cmd.cpp:103
xcommand_t function
Definition: cmd.cpp:482
#define ALIAS_HASH_SIZE
Definition: cmd.cpp:40
const char * filename
Definition: ioapi.h:41
memPool_t * com_aliasSysPool
Definition: common.cpp:68
void Cbuf_AddText(const char *format,...)
Adds command text at the end of the buffer.
Definition: cmd.cpp:126
void Cmd_TokenizeString(const char *text, bool macroExpand, bool replaceWhitespaces)
Parses the given string into command line tokens.
Definition: cmd.cpp:565
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
Command text buffering and command execution header.
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
bool Cmd_GenericCompleteFunction(char const *candidate, char const *partial, char const **match)
Definition: cmd.cpp:648
const char * description
Definition: cmd.cpp:481
static void * cmd_userdata
Definition: cmd.cpp:494
int maxsize
Definition: msg.h:30
static void Cmd_Exec_f(void)
Definition: cmd.cpp:352
memPool_t * com_cmdSysPool
Definition: common.cpp:69
void Cmd_TableRemoveList(const cmdList_t *cmdList)
Definition: cmd.cpp:859
#define Q_strvalid(string)
Definition: shared.h:141
void * userdata
Definition: cmd.cpp:484
void SZ_Clear(sizebuf_t *buf)
Definition: msg.cpp:36
void Cmd_ExecuteString(const char *text,...)
A complete command line has been parsed, so try to execute it.
Definition: cmd.cpp:1007
static bool cmdClosed
Definition: cmd.cpp:58
static cmd_function_t * cmd_functions
Definition: cmd.cpp:496
bool Cvar_Command(void)
Handles variable inspection and changing from the console.
Definition: cvar.cpp:708
void SZ_Write(sizebuf_t *buf, const void *data, int length)
Definition: msg.cpp:52
void * Cmd_Userdata(void)
Return the userdata of the called command.
Definition: cmd.cpp:534
#define MAX_STRING_TOKENS
Definition: defines.h:92
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
const char * name
Definition: cmd.h:87
static CmdListeners cmdListeners
Definition: cmd.cpp:54
void * Cmd_GetUserdata(const char *cmdName)
Fetches the userdata for a console command.
Definition: cmd.cpp:700
static void Cmd_Open_f(void)
Reopens the command buffer for writing.
Definition: cmd.cpp:68
byte * data
Definition: msg.h:29
static cmd_function_t * cmd_functions_hash[CMD_HASH_SIZE]
Definition: cmd.cpp:497
#define OBJZERO(obj)
Definition: shared.h:178
#define MAX_VAR
Definition: shared.h:36
bool Cmd_Exists(const char *cmdName)
Checks whether a function exists already.
Definition: cmd.cpp:887
void Cmd_BufClear(void)
Clears the argv vector and set argc to zero.
Definition: cmd.cpp:543
struct cmd_function_s * next
Definition: cmd.cpp:478
const char * Com_MacroExpandString(const char *text)
Expands strings with cvar values that are dereferenced by a '*cvar'.
Definition: common.cpp:607
int(* completeParam)(const char *partial, const char **match)
Definition: cmd.cpp:483
static wrapCache_t * hash[MAX_WRAP_HASH]
Definition: r_font.cpp:86
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
Message IO functions - handles byte ordering and avoids alignment errors.
std::vector< CmdListenerPtr > CmdListeners
Definition: cmd.cpp:52
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
Definition: cmd.h:86
int FS_Printf(qFILE *f, const char *msg,...)
Can print chunks for 1024 chars into a file.
Definition: files.cpp:1495
void(* xcommand_t)(void)
Definition: cmd.h:84
#define S_COLOR_GREEN
Definition: common.h:219
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
#define Q_strcasecmp(a, b)
Definition: shared.h:131
void Cbuf_Shutdown(void)
Definition: cmd.cpp:117
#define CMD_BUFFER_SIZE
Definition: cmd.cpp:101
#define HASH_Add(hash, elem, index)
Definition: common.h:430
#define Mem_FreePool(pool)
Definition: mem.h:37
bool Cbuf_AddLateCommands(void)
Adds command line parameters as script statements.
Definition: cmd.cpp:298
static sizebuf_t cmd_text
Definition: cmd.cpp:102
void SZ_Init(sizebuf_t *buf, byte *data, int length)
Definition: msg.cpp:29
void Cmd_ForwardToServer(void)
adds the current command line as a clc_stringcmd to the client message. things like action...
Definition: cl_main.cpp:98
struct cmd_alias_s * next
Definition: cmd.cpp:49
static char com_token[4096]
Definition: parse.cpp:32
const char * getName() const
Definition: cmd.cpp:486
void Cmd_AddUserdata(const char *cmdName, void *userdata)
Adds userdata to the console command.
Definition: cmd.cpp:724
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
void Cbuf_CopyToDefer(void)
Defers any outstanding commands.
Definition: cmd.cpp:191
struct cmd_alias_s cmd_alias_t
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
static void Cmd_Close_f(void)
Will no longer add any command to command buffer ...until cmd_close is false again.
Definition: cmd.cpp:79
void Cbuf_Init(void)
allocates an initial text buffer that will grow as needed
Definition: cmd.cpp:109
static void Cmd_Echo_f(void)
Just prints the rest of the line to the console.
Definition: cmd.cpp:383
void Cmd_Shutdown(void)
Definition: cmd.cpp:1145
static char * cmd_argv[MAX_STRING_TOKENS]
Definition: cmd.cpp:492
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
int Com_Argc(void)
Returns the script commandline argument count.
Definition: common.cpp:560
#define MAX_STRING_CHARS
Definition: defines.h:90
struct cmd_function_s * hash_next
Definition: cmd.cpp:479
Definition: msg.h:28
void Com_ClearArgv(int arg)
Reset com_argv entry to empty string.
Definition: common.cpp:580
static cmd_alias_t * cmd_alias_hash[ALIAS_HASH_SIZE]
Definition: cmd.cpp:56
static char cmd_args[MAX_STRING_CHARS]
Definition: cmd.cpp:493
void Cmd_TableCheck(void)
Check both the functiontable and the associated hashtable for invalid entries.
Definition: cmd.cpp:826
#define Mem_Free(ptr)
Definition: mem.h:35
unsigned int Com_HashKey(const char *name, int hashsize)
returns hash key for a string
Definition: shared.cpp:336
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
void Cmd_RegisterCmdListener(CmdListenerPtr listener)
Registers a command listener.
Definition: cmd.cpp:869
bool archive
Definition: cmd.cpp:47
definitions common between client and server, but not game lib
void Cmd_AddParamCompleteFunction(const char *cmdName, int(*function)(const char *partial, const char **match))
Definition: cmd.cpp:679
static int cmd_argc
Definition: cmd.cpp:491
static int Cmd_CompleteExecCommand(const char *partial, const char **match)
Autocomplete function for exec command.
Definition: cmd.cpp:1066
#define ALIAS_LOOP_COUNT
Definition: cmd.cpp:60
#define lengthof(x)
Definition: shared.h:105
const char * Cmd_GetCommandDesc(const char *cmdName)
Returns the command description for a given command.
Definition: cmd.cpp:629
struct cmd_function_s cmd_function_t
int cursize
Definition: msg.h:31
const char * Cvar_GetString(const char *varName)
Returns the value of cvar as string.
Definition: cvar.cpp:210
#define Q_streq(a, b)
Definition: shared.h:136
#define Mem_PoolStrDup(in, pool, tagNum)
Definition: mem.h:50
static cmd_alias_t * cmd_alias
Definition: cmd.cpp:55
int Cmd_CompleteCommandParameters(const char *command, const char *partial, const char **match)
Unix like tab completion for console commands parameters.
Definition: cmd.cpp:903
void Cbuf_InsertFromDefer(void)
Copies back any deferred commands.
Definition: cmd.cpp:201
void Cmd_Dummy_f(void)
Dummy binding if you don't want unknown commands forwarded to the server.
Definition: cmd.cpp:1083
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
void Cbuf_Execute(void)
Pulls off terminated lines of text from the command buffer and sends them through Cmd_ExecuteString...
Definition: cmd.cpp:214
static void Cmd_List_f(void)
List all available script interface functions.
Definition: cmd.cpp:1028
char name[MAX_ALIAS_NAME]
Definition: cmd.cpp:45
char name[MAX_OSPATH]
Definition: filesys.h:57
uint8_t byte
Definition: ufotypes.h:34
const char * name
Definition: cmd.cpp:480
void Cbuf_AddEarlyCommands(bool clear)
Adds command line parameters as script statements Commands lead with a +, and continue until another ...
Definition: cmd.cpp:275
#define MAX_ALIAS_NAME
Definition: cmd.cpp:42
char * Com_Chop(char *s)
Removed trailing whitespaces.
Definition: shared.cpp:48
static char defer_text_buf[CMD_BUFFER_SIZE]
Definition: cmd.cpp:104
void Cmd_WriteAliases(qFILE *f)
Write lines containing "aliasa alias value" for all aliases with the archive flag set to true...
Definition: cmd.cpp:454
const char * Cmd_Args(void)
Returns a single string containing argv(1) to argv(argc()-1)
Definition: cmd.cpp:526
#define DEBUG_COMMANDS
Definition: defines.h:58
static bool cmdWait
Definition: cmd.cpp:57
#define CMD_HASH_SIZE
Definition: cmd.cpp:475
void format(__printf__, 1, 2)))
void Cmd_TableAddList(const cmdList_t *cmdList)
Definition: cmd.cpp:853
void FS_FreeFile(void *buffer)
Definition: files.cpp:411
static cmd_function_t * Cmd_TableFind(const char *cmdName)
Definition: cmd.cpp:613