Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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