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