1 /*
2 * cmd.c - Quake script command processing module
3 * $Id: cmd.c 5430 2015-08-23 11:00:47Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "quakedef.h"
24
25 #define MAX_ALIAS_NAME 32
26 #define MAX_ARGS 80
27
28 static sizebuf_t cmd_text;
29 //static byte cmd_text_buf[8192];
30
31 cmd_source_t cmd_source;
32
33 typedef struct cmdalias_s
34 {
35 struct cmdalias_s *next;
36 char name[MAX_ALIAS_NAME];
37 char *value;
38 } cmdalias_t;
39
40 typedef struct cmd_function_s
41 {
42 struct cmd_function_s *next;
43 const char *name;
44 xcommand_t function;
45 } cmd_function_t;
46
47 static cmdalias_t *cmd_alias = NULL;
48 static cmd_function_t *cmd_functions = NULL;
49
50 static int cmd_argc;
51 static char *cmd_argv[MAX_ARGS];
52 static char cmd_null_string[] = "";
53 static const char *cmd_args = NULL;
54
55 static qboolean cmd_wait;
56
57
58 //=============================================================================
59
60 /*
61 ============
62 Cmd_Wait_f
63
64 Causes execution of the remainder of the command buffer to be delayed until
65 next frame. This allows commands like:
66 bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
67 ============
68 */
Cmd_Wait_f(void)69 static void Cmd_Wait_f (void)
70 {
71 cmd_wait = true;
72 }
73
74 /*
75 =============================================================================
76
77 COMMAND BUFFER
78
79 =============================================================================
80 */
81
82 /*
83 ============
84 Cbuf_Init
85 ============
86 */
Cbuf_Init(void)87 void Cbuf_Init (void)
88 {
89 // SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
90 SZ_Init (&cmd_text, NULL, 8192);
91 }
92
93
94 /*
95 ============
96 Cbuf_AddText
97
98 Adds command text at the end of the buffer
99 ============
100 */
Cbuf_AddText(const char * text)101 void Cbuf_AddText (const char *text)
102 {
103 int l;
104
105 l = strlen (text);
106
107 if (cmd_text.cursize + l >= cmd_text.maxsize)
108 {
109 Con_Printf ("%s: overflow\n", __thisfunc__);
110 return;
111 }
112 SZ_Write (&cmd_text, text, l);
113 }
114
115
116 /*
117 ============
118 Cbuf_InsertText
119
120 Adds command text immediately after the current command
121 Adds a \n to the text
122 FIXME: actually change the command buffer to do less copying
123 ============
124 */
Cbuf_InsertText(const char * text)125 void Cbuf_InsertText (const char *text)
126 {
127 char *temp;
128 int templen;
129
130 // copy off any commands still remaining in the exec buffer
131 templen = cmd_text.cursize;
132 if (templen)
133 {
134 temp = (char *) Z_Malloc (templen, Z_MAINZONE);
135 memcpy (temp, cmd_text.data, templen);
136 SZ_Clear (&cmd_text);
137 }
138 else
139 temp = NULL; // shut up compiler
140
141 // add the entire text of the file
142 Cbuf_AddText (text);
143 SZ_Write (&cmd_text, "\n", 1);
144 // add the copied off data
145 if (templen)
146 {
147 SZ_Write (&cmd_text, temp, templen);
148 Z_Free (temp);
149 }
150 }
151
152 /*
153 ============
154 Cbuf_Execute
155 ============
156 */
Cbuf_Execute(void)157 void Cbuf_Execute (void)
158 {
159 int i;
160 char *text;
161 char line[1024];
162 int quotes;
163
164 while (cmd_text.cursize)
165 {
166 // find a \n or ; line break
167 text = (char *)cmd_text.data;
168
169 quotes = 0;
170 for (i = 0; i < cmd_text.cursize; i++)
171 {
172 if (text[i] == '"')
173 quotes++;
174 if ( !(quotes&1) && text[i] == ';')
175 break; // don't break if inside a quoted string
176 if (text[i] == '\n')
177 break;
178 }
179
180 if (i > (int)sizeof(line) - 1)
181 {
182 memcpy (line, text, sizeof(line) - 1);
183 line[sizeof(line) - 1] = 0;
184 }
185 else
186 {
187 memcpy (line, text, i);
188 line[i] = 0;
189 }
190
191 // delete the text from the command buffer and move remaining commands down
192 // this is necessary because commands (exec, alias) can insert data at the
193 // beginning of the text buffer
194
195 if (i == cmd_text.cursize)
196 cmd_text.cursize = 0;
197 else
198 {
199 i++;
200 cmd_text.cursize -= i;
201 memmove (text, text + i, cmd_text.cursize);
202 }
203
204 // execute the command line
205 Cmd_ExecuteString (line, src_command);
206
207 if (cmd_wait)
208 { // skip out while text still remains in buffer, leaving it
209 // for next frame
210 cmd_wait = false;
211 break;
212 }
213 }
214 }
215
216 /*
217 ==============================================================================
218
219 SCRIPT COMMANDS
220
221 ==============================================================================
222 */
223
224 /*
225 ===============
226 Cmd_StuffCmds_f
227
228 Adds command line parameters as script statements
229 Commands lead with a +, and continue until a - or another +
230 quake +prog jctest.qp +cmd amlev1
231 quake -nosound +cmd amlev1
232 ===============
233 */
Cmd_StuffCmds_f(void)234 void Cmd_StuffCmds_f (void)
235 {
236 int i;
237 int s;
238 char *text;
239
240 s = 0;
241 for (i = 1; i < com_argc; i++)
242 {
243 if (!com_argv[i])
244 continue; // NEXTSTEP nulls out -NXHost
245 s += strlen (com_argv[i]) + 1;
246 }
247 if (!s)
248 return;
249
250 text = (char *) Z_Malloc (s+1, Z_MAINZONE);
251 text[0] = '\0';
252
253 for (i = 1; i < com_argc; i++)
254 {
255 if (!com_argv[i])
256 continue; // NEXTSTEP nulls out -NXHost
257 if (com_argv[i][0] != '+')
258 continue;
259 // found a command
260 if (text[0] != '\0')
261 strcat (text, " "); // separate it from previous one
262 strcat (text, &com_argv[i][1]);
263 if (i == com_argc - 1)
264 {
265 strcat (text, "\n"); // finished all args
266 break;
267 }
268 // add the arguments of the command
269 ++i;
270 for ( ; i < com_argc; i++)
271 {
272 if (com_argv[i][0] == '+' || com_argv[i][0] == '-')
273 {
274 // found a new command or a new command-line switch
275 strcat (text, "\n");
276 --i;
277 break;
278 }
279 strcat (text, " ");
280 strcat (text, com_argv[i]);
281 if (i == com_argc - 1)
282 strcat (text, "\n"); // finished all args
283 }
284 }
285
286 if (text[0] != '\0')
287 Cbuf_InsertText (text);
288
289 Z_Free (text);
290 }
291
292
293 /*
294 ===============
295 Cmd_Exec_f
296 ===============
297 */
Cmd_Exec_f(void)298 static void Cmd_Exec_f (void)
299 {
300 char *f;
301 int mark;
302
303 if (Cmd_Argc () != 2)
304 {
305 Con_Printf ("exec <filename> : execute a script file\n");
306 return;
307 }
308
309 // FIXME: is this safe freeing the hunk here???
310 mark = Hunk_LowMark ();
311 f = (char *)FS_LoadHunkFile (Cmd_Argv(1), NULL);
312 if (!f)
313 {
314 Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
315 return;
316 }
317 Con_Printf ("execing %s\n", Cmd_Argv(1));
318
319 Cbuf_InsertText (f);
320 Hunk_FreeToLowMark (mark);
321 }
322
323
324 /*
325 ===============
326 Cmd_Echo_f
327
328 Just prints the rest of the line to the console
329 ===============
330 */
Cmd_Echo_f(void)331 static void Cmd_Echo_f (void)
332 {
333 int i;
334
335 for (i = 1; i < Cmd_Argc(); i++)
336 Con_Printf ("%s ", Cmd_Argv(i));
337 Con_Printf ("\n");
338 }
339
340 /*
341 ===============
342 Cmd_Alias_f
343
344 Creates a new command that executes a command string (possibly ; seperated)
345 ===============
346 */
Cmd_Alias_f(void)347 static void Cmd_Alias_f (void)
348 {
349 cmdalias_t *a;
350 char cmd[1024];
351 int i, c;
352 const char *s;
353
354 if (Cmd_Argc() == 1)
355 {
356 Con_Printf ("Current alias commands:\n");
357 for (a = cmd_alias ; a ; a = a->next)
358 Con_Printf ("%s : %s\n", a->name, a->value);
359 return;
360 }
361
362 s = Cmd_Argv(1);
363
364 if (Cmd_Argc() == 2)
365 {
366 for (a = cmd_alias ; a ; a = a->next)
367 {
368 if ( !strcmp(s, a->name) )
369 {
370 Con_Printf ("%s : %s\n", s, a->value);
371 return;
372 }
373 }
374 Con_Printf ("No alias named %s\n", s);
375 return;
376 }
377
378 if (strlen(s) >= MAX_ALIAS_NAME)
379 {
380 Con_Printf ("Alias name is too long\n");
381 return;
382 }
383
384 // if the alias already exists, reuse it
385 for (a = cmd_alias ; a ; a = a->next)
386 {
387 if ( !strcmp(s, a->name) )
388 {
389 Z_Free (a->value);
390 break;
391 }
392 }
393
394 if (!a)
395 {
396 a = (cmdalias_t *) Z_Malloc (sizeof(cmdalias_t), Z_MAINZONE);
397 a->next = cmd_alias;
398 cmd_alias = a;
399 }
400 strcpy (a->name, s);
401
402 // copy the rest of the command line
403 cmd[0] = 0; // start out with a null string
404 c = Cmd_Argc();
405 for (i = 2; i < c; i++)
406 {
407 q_strlcat (cmd, Cmd_Argv(i), sizeof(cmd));
408 if (i != c - 1)
409 q_strlcat (cmd, " ", sizeof(cmd));
410 }
411 if (q_strlcat(cmd, "\n", sizeof(cmd)) >= sizeof(cmd))
412 {
413 Con_Printf("alias value too long!\n");
414 cmd[0] = '\n'; // nullify the string
415 cmd[1] = 0;
416 }
417
418 a->value = Z_Strdup (cmd);
419 }
420
421 /*
422 ===============
423 Cmd_Unalias_f
424
425 Delete an alias
426 ===============
427 */
Cmd_Unalias_f(void)428 void Cmd_Unalias_f (void)
429 {
430 cmdalias_t *prev = NULL, *a;
431
432 if (Cmd_Argc() != 2)
433 {
434 Con_Printf("unalias <name> : delete alias\n"
435 "unaliasall : delete all aliases\n");
436 return;
437 }
438
439 for (a = cmd_alias ; a ; a=a->next)
440 {
441 if ( !strcmp(Cmd_Argv(1), a->name) )
442 {
443 if (prev)
444 prev->next = a->next;
445 else
446 cmd_alias = a->next;
447
448 Z_Free (a->value);
449 Z_Free (a);
450 return;
451 }
452 prev = a;
453 }
454
455 Con_Printf ("No alias named %s\n", Cmd_Argv(1));
456 }
457
458 /*
459 ===============
460 Cmd_Unaliasall_f
461
462 Delete all aliases
463 ===============
464 */
Cmd_Unaliasall_f(void)465 void Cmd_Unaliasall_f (void)
466 {
467 cmdalias_t *a;
468
469 while (cmd_alias)
470 {
471 a = cmd_alias->next;
472 Z_Free(cmd_alias->value);
473 Z_Free(cmd_alias);
474 cmd_alias = a;
475 }
476 }
477
478 /*
479 =============================================================================
480
481 COMMAND EXECUTION
482
483 =============================================================================
484 */
485
486 /*
487 ============
488 Cmd_Argc
489 ============
490 */
Cmd_Argc(void)491 int Cmd_Argc (void)
492 {
493 return cmd_argc;
494 }
495
496 /*
497 ============
498 Cmd_Argv
499 ============
500 */
Cmd_Argv(int arg)501 const char *Cmd_Argv (int arg)
502 {
503 if (arg < 0 || arg >= cmd_argc)
504 return cmd_null_string;
505 return cmd_argv[arg];
506 }
507
508 /*
509 ============
510 Cmd_Args
511
512 Returns a single string containing argv(1) to argv(argc()-1)
513 ============
514 */
Cmd_Args(void)515 const char *Cmd_Args (void)
516 {
517 if (!cmd_args)
518 return cmd_null_string;
519 return cmd_args;
520 }
521
522
523 /*
524 ============
525 Cmd_TokenizeString
526
527 Parses the given string into command line tokens.
528 ============
529 */
Cmd_TokenizeString(const char * text)530 void Cmd_TokenizeString (const char *text)
531 {
532 int i;
533
534 // clear the args from the last string
535 for (i = 0; i < cmd_argc; i++)
536 Z_Free (cmd_argv[i]);
537
538 cmd_argc = 0;
539 cmd_args = NULL;
540
541 while (1)
542 {
543 // skip whitespace up to a /n
544 while (*text && *text <= ' ' && *text != '\n')
545 {
546 text++;
547 }
548
549 if (*text == '\n')
550 { // a newline seperates commands in the buffer
551 text++;
552 break;
553 }
554
555 if (!*text)
556 return;
557
558 if (cmd_argc == 1)
559 cmd_args = text;
560
561 text = COM_Parse (text);
562 if (!text)
563 return;
564
565 if (cmd_argc < MAX_ARGS)
566 {
567 cmd_argv[cmd_argc] = Z_Strdup (com_token);
568 cmd_argc++;
569 }
570 }
571 }
572
573
574 /*
575 ============
576 Cmd_AddCommand
577 ============
578 */
Cmd_AddCommand(const char * cmd_name,xcommand_t function)579 void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
580 {
581 cmd_function_t *cmd;
582
583 if (host_initialized) // because hunk allocation would get stomped
584 Sys_Error ("Cmd_AddCommand after host_initialized");
585
586 // fail if the command is a variable name
587 if (Cvar_VariableString(cmd_name)[0])
588 {
589 Con_Printf ("%s: %s already defined as a var\n", __thisfunc__, cmd_name);
590 return;
591 }
592
593 // fail if the command already exists
594 for (cmd = cmd_functions ; cmd ; cmd = cmd->next)
595 {
596 if ( !strcmp(cmd_name, cmd->name) )
597 {
598 Con_Printf ("%s: %s already defined\n", __thisfunc__, cmd_name);
599 return;
600 }
601 }
602
603 cmd = (cmd_function_t *) Hunk_AllocName (sizeof(cmd_function_t), "commands");
604 cmd->name = cmd_name;
605 cmd->function = function;
606 cmd->next = cmd_functions;
607 cmd_functions = cmd;
608 }
609
610 /*
611 ============
612 Cmd_Exists
613 ============
614 */
Cmd_Exists(const char * cmd_name)615 qboolean Cmd_Exists (const char *cmd_name)
616 {
617 cmd_function_t *cmd;
618
619 for (cmd = cmd_functions ; cmd ; cmd = cmd->next)
620 {
621 if ( !strcmp(cmd_name, cmd->name) )
622 return true;
623 }
624
625 return false;
626 }
627
628
629 /*
630 ============
631 Cmd_CheckCommand
632 ============
633 */
Cmd_CheckCommand(const char * partial)634 qboolean Cmd_CheckCommand (const char *partial)
635 {
636 cmd_function_t *cmd;
637 cmdalias_t *a;
638 cvar_t *var;
639
640 if (!partial || !partial[0])
641 return false;
642 for (cmd = cmd_functions ; cmd ; cmd = cmd->next)
643 {
644 if ( !strcmp(partial, cmd->name) )
645 return true;
646 }
647 var = Cvar_FindVarAfter ("", CVAR_NONE);
648 for ( ; var ; var = var->next)
649 {
650 if ( !strcmp(partial, var->name) )
651 return true;
652 }
653 for (a = cmd_alias ; a ; a = a->next)
654 {
655 if ( !strcmp(partial, a->name) )
656 return true;
657 }
658
659 return false;
660 }
661
662 /*
663 ============
664 Cmd_ExecuteString
665
666 A complete command line has been parsed, so try to execute it
667 FIXME: lookupnoadd the token to speed search?
668 ============
669 */
Cmd_ExecuteString(const char * text,cmd_source_t src)670 void Cmd_ExecuteString (const char *text, cmd_source_t src)
671 {
672 cmd_function_t *cmd;
673 cmdalias_t *a;
674
675 cmd_source = src;
676 Cmd_TokenizeString (text);
677
678 // execute the command line
679 if (!Cmd_Argc())
680 return; // no tokens
681
682 // check functions
683 for (cmd = cmd_functions ; cmd ; cmd = cmd->next)
684 {
685 if ( !q_strcasecmp(cmd_argv[0], cmd->name) )
686 {
687 #if defined(H2W)
688 if (!cmd->function)
689 # ifndef SERVERONLY
690 Cmd_ForwardToServer ();
691 # else
692 Sys_Printf ("FIXME: command %s has NULL handler function\n", cmd->name);
693 # endif
694 else
695 #endif
696 cmd->function ();
697
698 return;
699 }
700 }
701
702 // check alias
703 for (a = cmd_alias ; a ; a = a->next)
704 {
705 if ( !q_strcasecmp(cmd_argv[0], a->name) )
706 {
707 Cbuf_InsertText (a->value);
708 return;
709 }
710 }
711
712 // check cvars
713 if (!Cvar_Command())
714 Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
715 }
716
717 /*
718 ================
719 Cmd_CheckParm
720
721 Returns the position (1 to argc-1) in the command's argument list
722 where the given parameter apears, or 0 if not present
723 ================
724 */
Cmd_CheckParm(const char * parm)725 int Cmd_CheckParm (const char *parm)
726 {
727 int i;
728
729 if (!parm)
730 Sys_Error ("%s: null input\n", __thisfunc__);
731
732 for (i = 1; i < Cmd_Argc (); i++)
733 if ( !q_strcasecmp(parm, Cmd_Argv (i)) )
734 return i;
735
736 return 0;
737 }
738
739 #ifndef SERVERONLY
740 /*
741 ===============
742 Cmd_List_f
743
744 Lists the commands to the console
745 ===============
746 */
ListCommands(const char * prefix,const char ** buf,int pos)747 int ListCommands (const char *prefix, const char **buf, int pos)
748 {
749 cmd_function_t *cmd;
750 int i = 0;
751 int preLen = (prefix == NULL) ? 0 : strlen(prefix);
752
753 for (cmd = cmd_functions ; cmd ; cmd = cmd->next)
754 {
755 if (!preLen) // completion procedures always send a prefix
756 {
757 Con_Printf (" %s\n", cmd->name);
758 continue;
759 }
760
761 if ( !q_strncasecmp(prefix, cmd->name, preLen) )
762 {
763 if (!buf) // completion procedures always send a buf
764 {
765 Con_Printf (" %s\n", cmd->name);
766 continue;
767 }
768
769 if (pos+i < MAX_MATCHES)
770 buf[pos+i] = cmd->name;
771 else
772 break;
773
774 i++;
775 }
776 }
777
778 return i;
779 }
780
Cmd_List_f(void)781 static void Cmd_List_f(void)
782 {
783 if ( Cmd_Argc() > 1 )
784 ListCommands (Cmd_Argv(1), NULL, 0);
785 else
786 ListCommands (NULL, NULL, 0);
787 }
788
789 /*
790 ===============
791 Cmd_ListCvar_f
792
793 Lists the cvars to the console
794 ===============
795 */
ListCvars(const char * prefix,const char ** buf,int pos)796 int ListCvars (const char *prefix, const char **buf, int pos)
797 {
798 cvar_t *var;
799 int i = 0;
800 int preLen = (prefix == NULL) ? 0 : strlen(prefix);
801
802 var = Cvar_FindVarAfter ("", CVAR_NONE);
803 for ( ; var ; var = var->next)
804 {
805 if (!preLen) // completion procedures always send a prefix
806 {
807 Con_Printf (" %s\n", var->name);
808 continue;
809 }
810
811 if ( !q_strncasecmp(prefix, var->name, preLen) )
812 {
813 if (!buf) // completion procedures always send a buf
814 {
815 Con_Printf (" %s\n", var->name);
816 continue;
817 }
818
819 if (pos+i < MAX_MATCHES)
820 buf[pos+i] = var->name;
821 else
822 break;
823
824 i++;
825 }
826 }
827
828 return i;
829 }
830
Cmd_ListCvar_f(void)831 static void Cmd_ListCvar_f(void)
832 {
833 if ( Cmd_Argc() > 1 )
834 ListCvars (Cmd_Argv(1), NULL, 0);
835 else
836 ListCvars (NULL, NULL, 0);
837 }
838
839 /*
840 ===============
841 Cmd_ListAlias_f
842
843 Lists the cvars to the console
844 ===============
845 */
ListAlias(const char * prefix,const char ** buf,int pos)846 int ListAlias (const char *prefix, const char **buf, int pos)
847 {
848 cmdalias_t *a;
849 int i = 0;
850 int preLen = (prefix == NULL) ? 0 : strlen(prefix);
851
852 for (a = cmd_alias ; a ; a = a->next)
853 {
854 if (!preLen) // completion procedures always send a prefix
855 {
856 Con_Printf (" %s\n", a->name);
857 continue;
858 }
859
860 if ( !q_strncasecmp(prefix, a->name, preLen) )
861 {
862 if (!buf) // completion procedures always send a buf
863 {
864 Con_Printf (" %s\n", a->name);
865 continue;
866 }
867
868 if (pos+i < MAX_MATCHES)
869 buf[pos+i] = a->name;
870 else
871 break;
872
873 i++;
874 }
875 }
876
877 return i;
878 }
879
Cmd_ListAlias_f(void)880 static void Cmd_ListAlias_f(void)
881 {
882 if ( Cmd_Argc() > 1 )
883 ListAlias (Cmd_Argv(1), NULL, 0);
884 else
885 ListAlias (NULL, NULL, 0);
886 }
887
Cmd_WriteCommands_f(void)888 static void Cmd_WriteCommands_f (void)
889 {
890 FILE *FH;
891 cmd_function_t *cmd;
892 cvar_t *var;
893 cmdalias_t *a;
894
895 FH = fopen(FS_MakePath(FS_USERDIR,NULL,"commands.txt"), "w");
896 if (!FH)
897 {
898 return;
899 }
900
901 fprintf(FH,"\n\nConsole Commands:\n");
902 for (cmd = cmd_functions ; cmd ; cmd = cmd->next)
903 fprintf(FH, " %s\n", cmd->name);
904
905 fprintf(FH,"\n\nAlias Commands:\n");
906 for (a = cmd_alias ; a ; a = a->next)
907 fprintf(FH, " %s :\n\t%s\n", a->name, a->value);
908
909 fprintf(FH,"\n\nConsole Variables:\n");
910 var = Cvar_FindVarAfter ("", CVAR_NONE);
911 for ( ; var ; var = var->next)
912 fprintf(FH, " %s\n", var->name);
913
914 fclose(FH);
915 }
916 #endif
917
918 /*
919 ============
920 Cmd_Init
921 ============
922 */
Cmd_Init(void)923 void Cmd_Init (void)
924 {
925 //
926 // register our commands
927 //
928 Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
929 Cmd_AddCommand ("exec",Cmd_Exec_f);
930 Cmd_AddCommand ("echo",Cmd_Echo_f);
931 Cmd_AddCommand ("alias",Cmd_Alias_f);
932 Cmd_AddCommand ("unalias",Cmd_Unalias_f);
933 Cmd_AddCommand ("unaliasall",Cmd_Unaliasall_f);
934 Cmd_AddCommand ("wait", Cmd_Wait_f);
935 #ifndef SERVERONLY
936 Cmd_AddCommand ("commands", Cmd_WriteCommands_f);
937 Cmd_AddCommand ("cmdlist", Cmd_List_f);
938 Cmd_AddCommand ("cvarlist", Cmd_ListCvar_f);
939 Cmd_AddCommand ("aliaslist", Cmd_ListAlias_f);
940 #endif
941 }
942
943