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