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