20 cmd_handler_t function;
21 const char *help_text;
24 #define CMD_MAX_CMDS 1024
26 /* The list of cmds */
27 static hashtable cmd_hash;
28 static cmd_t *cmd_list[CMD_MAX_CMDS];
32 #define ALIAS_NAME_MAX 32
33 typedef struct cmd_alias_s
35 char name[ALIAS_NAME_MAX];
39 #define CMD_MAX_ALIASES 1024
41 /* The list of aliases */
42 static hashtable cmd_alias_hash;
43 static cmd_alias_t *cmd_alias_list[CMD_MAX_ALIASES];
44 static int Num_cmd_aliases;
47 typedef struct cmd_queue_s
50 struct cmd_queue_s *next;
53 /* The list of commands to be executed */
54 static cmd_queue_t *cmd_queue_head;
55 static cmd_queue_t *cmd_queue_tail;
58 /* number of cycles to wait before processing any commands */
59 static int cmd_queue_wait;
62 static cmd_t *cmd_findcommand(const char *cmd_name)
66 i = hashtable_search( &cmd_hash, cmd_name );
75 static cmd_alias_t *cmd_findalias(const char *alias_name )
79 i = hashtable_search( &cmd_alias_hash, alias_name );
84 return cmd_alias_list[i];
88 /* add a new console command */
89 void cmd_addcommand(const char *cmd_name, cmd_handler_t cmd_func, const char *cmd_help_text)
93 Assert(cmd_name != NULL);
95 if (cmd_findcommand(cmd_name))
98 con_printf(CON_NORMAL, "command %s already exists, not adding\n", cmd_name);
102 /* create command, insert to hashtable */
103 MALLOC(cmd, cmd_t, 1);
104 cmd->name = cmd_name;
105 cmd->function = cmd_func;
106 cmd->help_text = cmd_help_text;
108 hashtable_insert(&cmd_hash, cmd_name, Num_cmds);
109 con_printf(CON_DEBUG, "cmd_addcommand: added %s\n", cmd->name);
111 cmd_list[Num_cmds++] = cmd;
115 void cvar_cmd_set(int argc, char **argv);
118 /* execute a parsed command */
119 void cmd_execute(int argc, char **argv)
124 if ( (cmd = cmd_findcommand(argv[0])) )
126 con_printf(CON_DEBUG, "cmd_execute: executing %s\n", argv[0]);
127 cmd->function(argc, argv);
131 if ( (alias = cmd_findalias(argv[0])) && alias->value )
133 con_printf(CON_DEBUG, "cmd_execute: pushing alias \"%s\": %s\n", alias->name, alias->value);
134 cmd_insert(alias->value);
139 { // set value of cvar
140 char *new_argv[CMD_MAX_TOKENS];
144 for (i = 0; i < argc; i++)
145 new_argv[i+1] = argv[i];
146 cvar_cmd_set(argc + 1, new_argv);
151 /* Parse an input string */
152 void cmd_parse(char *input)
154 char buffer[CMD_MAX_LENGTH];
155 char *tokens[CMD_MAX_TOKENS];
159 Assert(input != NULL);
161 /* Strip leading spaces */
162 while( isspace(*input) ) { ++input; }
163 strncpy( buffer, input, sizeof(buffer) );
165 //printf("lead strip \"%s\"\n",buffer);
167 /* If command is empty, give up */
170 /* Strip trailing spaces */
171 for (i=l-1; i>0 && isspace(buffer[i]); i--) ;
173 //printf("trail strip \"%s\"\n",buffer);
175 /* Split into tokens */
180 for (i=1; i<l; i++) {
181 if (buffer[i] == '"') {
182 tokens[num_tokens - 1] = &buffer[++i];
183 while (i < l && buffer[i] != '"')
188 if (isspace(buffer[i]) || buffer[i] == '=') {
190 while (isspace(buffer[i+1]) && (i+1 < l)) i++;
191 tokens[num_tokens++] = &buffer[i+1];
195 /* Check for matching commands */
196 cmd_execute(num_tokens, tokens);
200 int cmd_queue_process(void)
204 while (!cmd_queue_wait && cmd_queue_head) {
205 cmd = cmd_queue_head;
206 cmd_queue_head = cmd_queue_head->next;
208 cmd_queue_tail = NULL;
210 con_printf(CON_DEBUG, "cmd_queue_process: processing %s\n", cmd->command_line);
211 cmd_parse(cmd->command_line); // Note, this may change the queue
213 d_free(cmd->command_line);
217 if (cmd_queue_wait > 0) {
219 if (Function_mode == FMODE_GAME) {
220 con_printf(CON_DEBUG, "cmd_queue_process: waiting\n");
229 /* execute until there are no commands left */
230 void cmd_queue_flush(void)
232 while (cmd_queue_process()) {
237 /* Add some commands to the queue to be executed */
238 void cmd_enqueue(int insert, char *input)
240 cmd_queue_t *new, *head, *tail;
241 char output[CMD_MAX_LENGTH];
244 Assert(input != NULL);
251 /* Strip leading spaces */
252 while(isspace(*input) || *input == ';')
255 /* If command is empty, give up */
259 /* Find the end of this line (\n, ;, or nul) */
266 } else if ( *input == '\n' || (!quoted && *input == ';') ) {
270 } while ((*optr++ = *input++));
273 /* make a new queue item, add it to list */
274 MALLOC(new, cmd_queue_t, 1);
275 new->command_line = d_strdup(output);
284 con_printf(CON_DEBUG, "cmd_enqueue: adding %s\n", output);
288 /* add our list to the head of the main list */
290 tail->next = cmd_queue_head;
292 cmd_queue_tail = tail;
294 cmd_queue_head = head;
295 con_printf(CON_DEBUG, "cmd_enqueue: added to front of list\n");
297 /* add our list to the tail of the main list */
299 cmd_queue_head = head;
301 cmd_queue_tail->next = head;
303 cmd_queue_tail = tail;
304 con_printf(CON_DEBUG, "cmd_enqueue: added to back of list\n");
308 void cmd_enqueuef(int insert, const char *fmt, ...)
311 char buf[CMD_MAX_LENGTH];
313 va_start (arglist, fmt);
314 vsnprintf(buf, sizeof(buf), fmt, arglist);
317 cmd_enqueue(insert, buf);
321 /* Attempt to autocomplete an input string */
322 const char *cmd_complete(char *input)
325 size_t len = strlen(input);
330 for (i = 0; i < Num_cmds; i++)
331 if (!strnicmp(input, cmd_list[i]->name, len))
332 return cmd_list[i]->name;
334 for (i = 0; i < Num_cmd_aliases; i++)
335 if (!strnicmp(input, cmd_alias_list[i]->name, len))
336 return cmd_alias_list[i]->name;
338 return cvar_complete(input);
343 void cmd_alias(int argc, char **argv)
346 char buf[CMD_MAX_LENGTH] = "";
350 con_printf(CON_NORMAL, "aliases:\n");
351 for (i = 0; i < Num_cmd_aliases; i++)
352 con_printf(CON_NORMAL, "%s: %s\n", cmd_alias_list[i]->name, cmd_alias_list[i]->value);
357 if ( (alias = cmd_findalias(argv[1])) && alias->value )
359 con_printf(CON_NORMAL, "%s: %s\n", alias->name, alias->value);
363 con_printf(CON_NORMAL, "alias: %s not found\n", argv[1]);
367 for (i = 2; i < argc; i++) {
369 strncat(buf, " ", sizeof(buf) - strlen(buf) - 1);
370 strncat(buf, argv[i], sizeof(buf) - strlen(buf) - 1);
373 if ( (alias = cmd_findalias(argv[1])) )
376 d_free(alias->value);
377 alias->value = d_strdup(buf);
381 MALLOC(alias, cmd_alias_t, 1);
382 strncpy(alias->name, argv[1], sizeof(alias->name));
383 alias->value = d_strdup(buf);
385 hashtable_insert(&cmd_alias_hash, argv[1], Num_cmd_aliases);
387 cmd_alias_list[Num_cmd_aliases++] = alias;
392 void cmd_unalias(int argc, char **argv)
396 if (argc < 2 || argc > 2) {
397 cmd_insertf("help %s", argv[0]);
401 alias = cmd_findalias(argv[1]);
403 if (!alias || !alias->value )
405 con_printf(CON_NORMAL, "unalias: %s not found\n", argv[1]);
409 d_free(alias->value);
411 //d_free(alias); // Can't remove from hashtable, so just leave it
415 /* echo to console */
416 void cmd_echo(int argc, char **argv)
418 char buf[CMD_MAX_LENGTH] = "";
421 for (i = 1; i < argc; i++) {
423 strncat(buf, " ", sizeof(buf) - strlen(buf) - 1);
424 strncat(buf, argv[i], sizeof(buf) - strlen(buf) - 1);
426 con_printf(CON_NORMAL, "%s\n", buf);
430 void cmd_exec(int argc, char **argv) {
431 cmd_queue_t *new, *head, *tail;
433 char line[CMD_MAX_LENGTH] = "";
435 if (argc < 2 || argc > 2) {
436 cmd_insertf("help %s", argv[0]);
442 f = PHYSFSX_openReadBuffered(argv[1]);
444 con_printf(CON_CRITICAL, "exec: %s not found\n", argv[1]);
447 while (PHYSFSX_gets(f, line)) {
448 /* make a new queue item, add it to list */
449 MALLOC(new, cmd_queue_t, 1);
450 new->command_line = d_strdup(line);
459 con_printf(CON_DEBUG, "cmd_exec: adding %s\n", line);
463 /* add our list to the head of the main list */
465 tail->next = cmd_queue_head;
467 cmd_queue_tail = tail;
469 cmd_queue_head = head;
470 con_printf(CON_DEBUG, "cmd_exec: added to front of list\n");
475 void cmd_help(int argc, char **argv)
480 cmd_insertf("help %s", argv[0]);
487 con_printf(CON_NORMAL, "Available commands:\n");
488 for (i = 0; i < Num_cmds; i++)
489 con_printf(CON_NORMAL, " %s\n", cmd_list[i]->name);
494 cmd = cmd_findcommand(argv[1]);
497 con_printf(CON_URGENT, "Command %s not found\n", argv[1]);
501 if (!cmd->help_text) {
502 con_printf(CON_NORMAL, "%s: no help found\n", argv[1]);
506 con_printf(CON_NORMAL, "%s\n", cmd->help_text);
511 void cmd_wait(int argc, char **argv)
514 cmd_insertf("help %s", argv[0]);
521 cmd_queue_wait = atoi(argv[1]);
528 d_free(cmd_list[Num_cmds]);
530 while (Num_cmd_aliases--)
532 d_free(cmd_alias_list[Num_cmd_aliases]->value);
533 d_free(cmd_alias_list[Num_cmd_aliases]);
536 hashtable_free(&cmd_hash);
537 hashtable_free(&cmd_alias_hash);
543 hashtable_init(&cmd_hash, CMD_MAX_CMDS);
544 hashtable_init(&cmd_alias_hash, CMD_MAX_ALIASES);
546 cmd_addcommand("alias", cmd_alias, "alias <name> <commands>\n" " define <name> as an alias for <commands>\n"
547 "alias <name>\n" " show the current definition of <name>\n"
548 "alias\n" " show all defined aliases");
549 cmd_addcommand("unalias", cmd_unalias, "unalias <name>\n" " undefine the alias <name>");
550 cmd_addcommand("echo", cmd_echo, "echo [text]\n" " write <text> to the console");
551 cmd_addcommand("exec", cmd_exec, "exec <file>\n" " execute <file>");
552 cmd_addcommand("help", cmd_help, "help [command]\n" " get help for <command>, or list all commands if not specified.");
553 cmd_addcommand("wait", cmd_wait, "usage: wait [n]\n" " stop processing commands, resume in <n> cycles (default 1)");