]> icculus.org git repositories - divverent/darkplaces.git/blob - cmd.c
skip bbox check on bmodels because it is fast enough to trace against their hull...
[divverent/darkplaces.git] / cmd.c
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 #define MAX_ALIAS_NAME  32
25
26 typedef struct cmdalias_s
27 {
28         struct cmdalias_s       *next;
29         char    name[MAX_ALIAS_NAME];
30         char    *value;
31 } cmdalias_t;
32
33 static cmdalias_t *cmd_alias;
34
35 static qboolean cmd_wait;
36
37 static mempool_t *cmd_mempool;
38
39 //=============================================================================
40
41 /*
42 ============
43 Cmd_Wait_f
44
45 Causes execution of the remainder of the command buffer to be delayed until
46 next frame.  This allows commands like:
47 bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
48 ============
49 */
50 static void Cmd_Wait_f (void)
51 {
52         cmd_wait = true;
53 }
54
55 /*
56 =============================================================================
57
58                                                 COMMAND BUFFER
59
60 =============================================================================
61 */
62
63 static sizebuf_t        cmd_text;
64
65 /*
66 ============
67 Cbuf_Init
68 ============
69 */
70 void Cbuf_Init (void)
71 {
72         // LordHavoc: inreased this from 8192 to 32768
73         SZ_Alloc (&cmd_text, 32768, "command buffer"); // space for commands and script files
74 }
75
76
77 /*
78 ============
79 Cbuf_AddText
80
81 Adds command text at the end of the buffer
82 ============
83 */
84 void Cbuf_AddText (char *text)
85 {
86         int             l;
87
88         l = strlen (text);
89
90         if (cmd_text.cursize + l >= cmd_text.maxsize)
91         {
92                 Con_Printf ("Cbuf_AddText: overflow\n");
93                 return;
94         }
95
96         SZ_Write (&cmd_text, text, strlen (text));
97 }
98
99
100 /*
101 ============
102 Cbuf_InsertText
103
104 Adds command text immediately after the current command
105 Adds a \n to the text
106 FIXME: actually change the command buffer to do less copying
107 ============
108 */
109 void Cbuf_InsertText (char *text)
110 {
111         char    *temp;
112         int             templen;
113
114 // copy off any commands still remaining in the exec buffer
115         templen = cmd_text.cursize;
116         if (templen)
117         {
118                 temp = Z_Malloc (templen);
119                 memcpy (temp, cmd_text.data, templen);
120                 SZ_Clear (&cmd_text);
121         }
122         else
123                 temp = NULL;    // shut up compiler
124
125 // add the entire text of the file
126         Cbuf_AddText (text);
127
128 // add the copied off data
129         if (templen)
130         {
131                 SZ_Write (&cmd_text, temp, templen);
132                 Z_Free (temp);
133         }
134 }
135
136 /*
137 ============
138 Cbuf_Execute
139 ============
140 */
141 void Cbuf_Execute (void)
142 {
143         int             i;
144         char    *text;
145         char    line[1024];
146         int             quotes;
147
148         while (cmd_text.cursize)
149         {
150 // find a \n or ; line break
151                 text = (char *)cmd_text.data;
152
153                 quotes = 0;
154                 for (i=0 ; i< cmd_text.cursize ; i++)
155                 {
156                         if (text[i] == '"')
157                                 quotes++;
158                         if ( !(quotes&1) &&  text[i] == ';')
159                                 break;  // don't break if inside a quoted string
160                         if (text[i] == '\n')
161                                 break;
162                 }
163
164                 memcpy (line, text, i);
165                 line[i] = 0;
166
167 // delete the text from the command buffer and move remaining commands down
168 // this is necessary because commands (exec, alias) can insert data at the
169 // beginning of the text buffer
170
171                 if (i == cmd_text.cursize)
172                         cmd_text.cursize = 0;
173                 else
174                 {
175                         i++;
176                         cmd_text.cursize -= i;
177                         memcpy (text, text+i, cmd_text.cursize);
178                 }
179
180 // execute the command line
181                 Cmd_ExecuteString (line, src_command);
182
183                 if (cmd_wait)
184                 {       // skip out while text still remains in buffer, leaving it
185                         // for next frame
186                         cmd_wait = false;
187                         break;
188                 }
189         }
190 }
191
192 /*
193 ==============================================================================
194
195                                                 SCRIPT COMMANDS
196
197 ==============================================================================
198 */
199
200 /*
201 ===============
202 Cmd_StuffCmds_f
203
204 Adds command line parameters as script statements
205 Commands lead with a +, and continue until a - or another +
206 quake +prog jctest.qp +cmd amlev1
207 quake -nosound +cmd amlev1
208 ===============
209 */
210 void Cmd_StuffCmds_f (void)
211 {
212         int             i, j;
213         int             s;
214         char    *text, *build, c;
215
216         if (Cmd_Argc () != 1)
217         {
218                 Con_Printf ("stuffcmds : execute command line parameters\n");
219                 return;
220         }
221
222 // build the combined string to parse from
223         s = 0;
224         for (i=1 ; i<com_argc ; i++)
225         {
226                 if (!com_argv[i])
227                         continue;               // NEXTSTEP nulls out -NXHost
228                 s += strlen (com_argv[i]) + 1;
229         }
230         if (!s)
231                 return;
232
233         text = Z_Malloc (s+1);
234         text[0] = 0;
235         for (i=1 ; i<com_argc ; i++)
236         {
237                 if (!com_argv[i])
238                         continue;               // NEXTSTEP nulls out -NXHost
239                 strcat (text,com_argv[i]);
240                 if (i != com_argc-1)
241                         strcat (text, " ");
242         }
243
244 // pull out the commands
245         build = Z_Malloc (s+1);
246         build[0] = 0;
247
248         for (i=0 ; i<s-1 ; i++)
249         {
250                 if (text[i] == '+')
251                 {
252                         i++;
253
254                         for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
255                                 ;
256
257                         c = text[j];
258                         text[j] = 0;
259
260                         strcat (build, text+i);
261                         strcat (build, "\n");
262                         text[j] = c;
263                         i = j-1;
264                 }
265         }
266
267         if (build[0])
268                 Cbuf_InsertText (build);
269
270         Z_Free (text);
271         Z_Free (build);
272 }
273
274
275 /*
276 ===============
277 Cmd_Exec_f
278 ===============
279 */
280 static void Cmd_Exec_f (void)
281 {
282         char    *f;
283
284         if (Cmd_Argc () != 2)
285         {
286                 Con_Printf ("exec <filename> : execute a script file\n");
287                 return;
288         }
289
290         f = (char *)COM_LoadFile (Cmd_Argv(1), false);
291         if (!f)
292         {
293                 Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
294                 return;
295         }
296         Con_Printf ("execing %s\n",Cmd_Argv(1));
297
298         Cbuf_InsertText (f);
299         Mem_Free(f);
300 }
301
302
303 /*
304 ===============
305 Cmd_Echo_f
306
307 Just prints the rest of the line to the console
308 ===============
309 */
310 static void Cmd_Echo_f (void)
311 {
312         int             i;
313
314         for (i=1 ; i<Cmd_Argc() ; i++)
315                 Con_Printf ("%s ",Cmd_Argv(i));
316         Con_Printf ("\n");
317 }
318
319 /*
320 ===============
321 Cmd_Alias_f
322
323 Creates a new command that executes a command string (possibly ; seperated)
324 ===============
325 */
326
327 static char *CopyString (char *in)
328 {
329         char    *out;
330
331         out = Z_Malloc (strlen(in)+1);
332         strcpy (out, in);
333         return out;
334 }
335
336 static void Cmd_Alias_f (void)
337 {
338         cmdalias_t      *a;
339         char            cmd[1024];
340         int                     i, c;
341         char            *s;
342
343         if (Cmd_Argc() == 1)
344         {
345                 Con_Printf ("Current alias commands:\n");
346                 for (a = cmd_alias ; a ; a=a->next)
347                         Con_Printf ("%s : %s\n", a->name, a->value);
348                 return;
349         }
350
351         s = Cmd_Argv(1);
352         if (strlen(s) >= MAX_ALIAS_NAME)
353         {
354                 Con_Printf ("Alias name is too long\n");
355                 return;
356         }
357
358         // if the alias already exists, reuse it
359         for (a = cmd_alias ; a ; a=a->next)
360         {
361                 if (!strcmp(s, a->name))
362                 {
363                         Z_Free (a->value);
364                         break;
365                 }
366         }
367
368         if (!a)
369         {
370                 a = Z_Malloc (sizeof(cmdalias_t));
371                 a->next = cmd_alias;
372                 cmd_alias = a;
373         }
374         strcpy (a->name, s);
375
376 // copy the rest of the command line
377         cmd[0] = 0;             // start out with a null string
378         c = Cmd_Argc();
379         for (i=2 ; i< c ; i++)
380         {
381                 strcat (cmd, Cmd_Argv(i));
382                 if (i != c)
383                         strcat (cmd, " ");
384         }
385         strcat (cmd, "\n");
386
387         a->value = CopyString (cmd);
388 }
389
390 /*
391 =============================================================================
392
393                                         COMMAND EXECUTION
394
395 =============================================================================
396 */
397
398 typedef struct cmd_function_s
399 {
400         struct cmd_function_s   *next;
401         char                                    *name;
402         xcommand_t                              function;
403 } cmd_function_t;
404
405
406 #define MAX_ARGS                80
407
408 static int cmd_argc;
409 static char *cmd_argv[MAX_ARGS];
410 static char *cmd_null_string = "";
411 static char *cmd_args = NULL;
412
413 cmd_source_t cmd_source;
414
415
416 static cmd_function_t *cmd_functions;           // possible commands to execute
417
418 /*
419 ========
420 Cmd_List
421
422         CmdList Added by EvilTypeGuy eviltypeguy@qeradiant.com
423         Thanks to Matthias "Maddes" Buecher, http://www.inside3d.com/qip/
424
425 ========
426 */
427 static void Cmd_List_f (void)
428 {
429         cmd_function_t  *cmd;
430         char                    *partial;
431         int                             len;
432         int                             count;
433
434         if (Cmd_Argc() > 1) {
435                 partial = Cmd_Argv (1);
436                 len = strlen(partial);
437         } else {
438                 partial = NULL;
439                 len = 0;
440         }
441
442         count = 0;
443         for (cmd = cmd_functions; cmd; cmd = cmd->next) {
444                 if (partial && strncmp(partial, cmd->name, len))
445                         continue;
446                 Con_Printf ("%s\n", cmd->name);
447                 count++;
448         }
449
450         Con_Printf ("%i Command%s", count, (count > 1) ? "s" : "");
451         if (partial)
452                 Con_Printf(" beginning with \"%s\"", partial);
453
454         Con_Printf ("\n\n");
455 }
456
457 /*
458 ============
459 Cmd_Init
460 ============
461 */
462 void Cmd_Init (void)
463 {
464         cmd_mempool = Mem_AllocPool("commands");
465
466 //
467 // register our commands
468 //
469         Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
470         Cmd_AddCommand ("exec",Cmd_Exec_f);
471         Cmd_AddCommand ("echo",Cmd_Echo_f);
472         Cmd_AddCommand ("alias",Cmd_Alias_f);
473         Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
474         Cmd_AddCommand ("wait", Cmd_Wait_f);
475         Cmd_AddCommand ("cmdlist", Cmd_List_f);         // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
476         Cmd_AddCommand ("cvarlist", Cvar_List_f);       // 2000-01-09 CmdList, CvarList commands
477                                                                                                 // By Matthias "Maddes" Buecher
478 }
479
480 /*
481 ============
482 Cmd_Argc
483 ============
484 */
485 int             Cmd_Argc (void)
486 {
487         return cmd_argc;
488 }
489
490 /*
491 ============
492 Cmd_Argv
493 ============
494 */
495 char    *Cmd_Argv (int arg)
496 {
497         if (arg >= cmd_argc )
498                 return cmd_null_string;
499         return cmd_argv[arg];
500 }
501
502 /*
503 ============
504 Cmd_Args
505 ============
506 */
507 char    *Cmd_Args (void)
508 {
509         return cmd_args;
510 }
511
512
513 #if 1
514 #define CMD_TOKENIZELENGTH 4096
515 char cmd_tokenizebuffer[CMD_TOKENIZELENGTH];
516 #endif
517
518 /*
519 ============
520 Cmd_TokenizeString
521
522 Parses the given string into command line tokens.
523 ============
524 */
525 static void Cmd_TokenizeString (char *text)
526 {
527         int l;
528 #ifdef CMD_TOKENIZELENGTH
529         int pos;
530         pos = 0;
531 #else
532         int i;
533 // clear the args from the last string
534         for (i=0 ; i<cmd_argc ; i++)
535                 Z_Free (cmd_argv[i]);
536 #endif
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                         l = strlen(com_token) + 1;
568 #ifdef CMD_TOKENIZELENGTH
569                         if (pos + l > CMD_TOKENIZELENGTH)
570                                 Sys_Error("Cmd_TokenizeString: ran out of %i character buffer space for command arguements\n", CMD_TOKENIZELENGTH);
571                         cmd_argv[cmd_argc] = cmd_tokenizebuffer + pos;
572                         pos += l;
573 #else
574                         cmd_argv[cmd_argc] = Z_Malloc (l);
575 #endif
576                         strcpy (cmd_argv[cmd_argc], com_token);
577                         cmd_argc++;
578                 }
579         }
580
581 }
582
583
584 /*
585 ============
586 Cmd_AddCommand
587 ============
588 */
589 void    Cmd_AddCommand (char *cmd_name, xcommand_t function)
590 {
591         cmd_function_t  *cmd;
592
593 //      if (host_initialized)   // because hunk allocation would get stomped
594 //              Sys_Error ("Cmd_AddCommand after host_initialized");
595
596 // fail if the command is a variable name
597         if (Cvar_VariableString(cmd_name)[0])
598         {
599                 Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
600                 return;
601         }
602
603 // fail if the command already exists
604         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
605         {
606                 if (!strcmp (cmd_name, cmd->name))
607                 {
608                         Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
609                         return;
610                 }
611         }
612
613         cmd = Mem_Alloc(cmd_mempool, sizeof(cmd_function_t));
614         cmd->name = cmd_name;
615         cmd->function = function;
616         cmd->next = cmd_functions;
617         cmd_functions = cmd;
618 }
619
620 /*
621 ============
622 Cmd_Exists
623 ============
624 */
625 qboolean        Cmd_Exists (char *cmd_name)
626 {
627         cmd_function_t  *cmd;
628
629         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
630                 if (!strcmp (cmd_name,cmd->name))
631                         return true;
632
633         return false;
634 }
635
636
637
638 /*
639 ============
640 Cmd_CompleteCommand
641 ============
642 */
643 char *Cmd_CompleteCommand (char *partial)
644 {
645         cmd_function_t  *cmd;
646         int                             len;
647
648         len = strlen(partial);
649
650         if (!len)
651                 return NULL;
652
653 // check functions
654         for (cmd = cmd_functions; cmd; cmd = cmd->next)
655                 if (!strncmp(partial, cmd->name, len))
656                         return cmd->name;
657
658         return NULL;
659 }
660
661 /*
662         Cmd_CompleteCountPossible
663
664         New function for tab-completion system
665         Added by EvilTypeGuy
666         Thanks to Fett erich@heintz.com
667         Thanks to taniwha
668
669 */
670 int Cmd_CompleteCountPossible (char *partial)
671 {
672         cmd_function_t  *cmd;
673         int                             len;
674         int                             h;
675
676         h = 0;
677         len = strlen(partial);
678
679         if (!len)
680                 return 0;
681
682         // Loop through the command list and count all partial matches
683         for (cmd = cmd_functions; cmd; cmd = cmd->next)
684                 if (!strncasecmp(partial, cmd->name, len))
685                         h++;
686
687         return h;
688 }
689
690 /*
691         Cmd_CompleteBuildList
692
693         New function for tab-completion system
694         Added by EvilTypeGuy
695         Thanks to Fett erich@heintz.com
696         Thanks to taniwha
697
698 */
699 char **Cmd_CompleteBuildList (char *partial)
700 {
701         cmd_function_t  *cmd;
702         int                             len = 0;
703         int                             bpos = 0;
704         int                             sizeofbuf = (Cmd_CompleteCountPossible (partial) + 1) * sizeof (char *);
705         char                    **buf;
706
707         len = strlen(partial);
708         buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
709         // Loop through the alias list and print all matches
710         for (cmd = cmd_functions; cmd; cmd = cmd->next)
711                 if (!strncasecmp(partial, cmd->name, len))
712                         buf[bpos++] = cmd->name;
713
714         buf[bpos] = NULL;
715         return buf;
716 }
717
718 /*
719         Cmd_CompleteAlias
720
721         New function for tab-completion system
722         Added by EvilTypeGuy
723         Thanks to Fett erich@heintz.com
724         Thanks to taniwha
725
726 */
727 char *Cmd_CompleteAlias (char * partial)
728 {
729         cmdalias_t      *alias;
730         int                     len;
731
732         len = strlen(partial);
733
734         if (!len)
735                 return NULL;
736
737         // Check functions
738         for (alias = cmd_alias; alias; alias = alias->next)
739                 if (!strncasecmp(partial, alias->name, len))
740                         return alias->name;
741
742         return NULL;
743 }
744
745 /*
746         Cmd_CompleteAliasCountPossible
747
748         New function for tab-completion system
749         Added by EvilTypeGuy
750         Thanks to Fett erich@heintz.com
751         Thanks to taniwha
752
753 */
754 int Cmd_CompleteAliasCountPossible (char *partial)
755 {
756         cmdalias_t      *alias;
757         int                     len;
758         int                     h;
759
760         h = 0;
761
762         len = strlen(partial);
763
764         if (!len)
765                 return 0;
766
767         // Loop through the command list and count all partial matches
768         for (alias = cmd_alias; alias; alias = alias->next)
769                 if (!strncasecmp(partial, alias->name, len))
770                         h++;
771
772         return h;
773 }
774
775 /*
776         Cmd_CompleteAliasBuildList
777
778         New function for tab-completion system
779         Added by EvilTypeGuy
780         Thanks to Fett erich@heintz.com
781         Thanks to taniwha
782
783 */
784 char **Cmd_CompleteAliasBuildList (char *partial)
785 {
786         cmdalias_t      *alias;
787         int                     len = 0;
788         int                     bpos = 0;
789         int                     sizeofbuf = (Cmd_CompleteAliasCountPossible (partial) + 1) * sizeof (char *);
790         char            **buf;
791
792         len = strlen(partial);
793         buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
794         // Loop through the alias list and print all matches
795         for (alias = cmd_alias; alias; alias = alias->next)
796                 if (!strncasecmp(partial, alias->name, len))
797                         buf[bpos++] = alias->name;
798
799         buf[bpos] = NULL;
800         return buf;
801 }
802
803 /*
804 ============
805 Cmd_ExecuteString
806
807 A complete command line has been parsed, so try to execute it
808 FIXME: lookupnoadd the token to speed search?
809 ============
810 */
811 void    Cmd_ExecuteString (char *text, cmd_source_t src)
812 {
813         cmd_function_t  *cmd;
814         cmdalias_t              *a;
815
816         cmd_source = src;
817         Cmd_TokenizeString (text);
818
819 // execute the command line
820         if (!Cmd_Argc())
821                 return;         // no tokens
822
823 // check functions
824         for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
825         {
826                 if (!Q_strcasecmp (cmd_argv[0],cmd->name))
827                 {
828                         cmd->function ();
829                         return;
830                 }
831         }
832
833 // check alias
834         for (a=cmd_alias ; a ; a=a->next)
835         {
836                 if (!Q_strcasecmp (cmd_argv[0], a->name))
837                 {
838                         Cbuf_InsertText (a->value);
839                         return;
840                 }
841         }
842
843 // check cvars
844         if (!Cvar_Command ())
845                 Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
846 }
847
848
849 /*
850 ===================
851 Cmd_ForwardToServer
852
853 Sends the entire command line over to the server
854 ===================
855 */
856 void Cmd_ForwardToServer (void)
857 {
858         if (cls.state != ca_connected)
859         {
860                 Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
861                 return;
862         }
863
864         if (cls.demoplayback)
865                 return;         // not really connected
866
867         MSG_WriteByte (&cls.message, clc_stringcmd);
868         if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)
869         {
870                 SZ_Print (&cls.message, Cmd_Argv(0));
871                 SZ_Print (&cls.message, " ");
872         }
873         if (Cmd_Argc() > 1)
874                 SZ_Print (&cls.message, Cmd_Args());
875         else
876                 SZ_Print (&cls.message, "\n");
877 }
878
879
880 /*
881 ================
882 Cmd_CheckParm
883
884 Returns the position (1 to argc-1) in the command's argument list
885 where the given parameter apears, or 0 if not present
886 ================
887 */
888
889 int Cmd_CheckParm (char *parm)
890 {
891         int i;
892
893         if (!parm)
894                 Sys_Error ("Cmd_CheckParm: NULL");
895
896         for (i = 1; i < Cmd_Argc (); i++)
897                 if (!Q_strcasecmp (parm, Cmd_Argv (i)))
898                         return i;
899
900         return 0;
901 }
902