]> icculus.org git repositories - btb/d2x.git/blob - main/cmd.c
more warnings
[btb/d2x.git] / main / cmd.c
1 #ifdef HAVE_CONFIG_H
2 #include <conf.h>
3 #endif
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
9
10 #include "pstypes.h"
11 #include "cmd.h"
12 #include "console.h"
13 #include "error.h"
14 #include "u_mem.h"
15 #include "strutil.h"
16 #include "inferno.h"
17
18
19 typedef struct cmd_s
20 {
21         char          *name;
22         cmd_handler_t function;
23         struct cmd_s  *next;
24 } cmd_t;
25
26 /* The list of cmds */
27 static cmd_t *cmd_list = NULL;
28
29
30 #define ALIAS_NAME_MAX 32
31 typedef struct cmd_alias_s
32 {
33         char           name[ALIAS_NAME_MAX];
34         char           *value;
35         struct cmd_alias_s *next;
36 } cmd_alias_t;
37
38 /* The list of aliases */
39 static cmd_alias_t *cmd_alias_list = NULL;
40
41
42 /* add a new console command */
43 void cmd_addcommand(char *cmd_name, cmd_handler_t cmd_func)
44 {
45         cmd_t *cmd;
46
47         Assert(cmd_name != NULL);
48
49         for (cmd = cmd_list; cmd; cmd = cmd->next) {
50                 if (!stricmp(cmd_name, cmd->name))
51                 {
52                         Int3();
53                         con_printf(CON_NORMAL, "command %s already exists, not adding\n", cmd_name);
54                         return;
55                 }
56         }
57
58         /* create command, insert at front of list */
59         MALLOC(cmd, cmd_t, 1);
60         cmd->name = cmd_name;
61         cmd->function = cmd_func;
62         cmd->next = cmd_list;
63         con_printf(CON_DEBUG, "cmd_addcommand: added %s\n", cmd->name);
64         cmd_list = cmd;
65 }
66
67
68 typedef struct cmd_queue_s
69 {
70         char *command_line;
71         struct cmd_queue_s *next;
72 } cmd_queue_t;
73
74 /* The list of commands to be executed */
75 static cmd_queue_t *cmd_queue_head = NULL;
76 static cmd_queue_t *cmd_queue_tail = NULL;
77
78
79 void cvar_cmd_set(int argc, char **argv);
80
81
82 /* execute a parsed command */
83 void cmd_execute(int argc, char **argv)
84 {
85         cmd_t *cmd;
86         cmd_alias_t *alias;
87
88         for (cmd = cmd_list; cmd; cmd = cmd->next) {
89                 if (!stricmp(argv[0], cmd->name)) {
90                         con_printf(CON_DEBUG, "cmd_execute: executing %s\n", argv[0]);
91                         cmd->function(argc, argv);
92                         return;
93                 }
94         }
95
96         for (alias = cmd_alias_list; alias; alias = alias->next) {
97                 if (!stricmp(argv[0], alias->name)) {
98                         con_printf(CON_DEBUG, "cmd_execute: pushing alias \"%s\": %s\n", alias->name, alias->value);
99                         cmd_insert(alias->value);
100                         return;
101                 }
102         }
103
104         /* Otherwise */
105         {  // set value of cvar
106                 char *new_argv[argc+1];
107                 int i;
108
109                 new_argv[0] = "set";
110                 for (i = 0; i < argc; i++)
111                         new_argv[i+1] = argv[i];
112                 cvar_cmd_set(argc + 1, new_argv);
113         }
114 }
115
116
117 /* Parse an input string */
118 void cmd_parse(char *input)
119 {
120         char buffer[CMD_MAX_LENGTH];
121         char *tokens[CMD_MAX_TOKENS];
122         int num_tokens;
123         int i, l;
124
125         Assert(input != NULL);
126         
127         /* Strip leading spaces */
128         for (i=0; isspace(input[i]); i++) ;
129         strncpy( buffer, &input[i], CMD_MAX_LENGTH );
130
131         //printf("lead strip \"%s\"\n",buffer);
132         l = (int)strlen(buffer);
133         /* If command is empty, give up */
134         if (l==0) return;
135
136         /* Strip trailing spaces */
137         for (i=l-1; i>0 && isspace(buffer[i]); i--) ;
138         buffer[i+1] = 0;
139         //printf("trail strip \"%s\"\n",buffer);
140
141         /* Split into tokens */
142         l = (int)strlen(buffer);
143         num_tokens = 1;
144
145         tokens[0] = buffer;
146         for (i=1; i<l; i++) {
147                 if (buffer[i] == '"') {
148                         tokens[num_tokens - 1] = &buffer[++i];
149                         while (i < l && buffer[i] != '"')
150                                 i++;
151                         buffer[i] = 0;
152                         continue;
153                 }
154                 if (isspace(buffer[i]) || buffer[i] == '=') {
155                         buffer[i] = 0;
156                         while (isspace(buffer[i+1]) && (i+1 < l)) i++;
157                         tokens[num_tokens++] = &buffer[i+1];
158                 }
159         }
160
161         /* Check for matching commands */
162         cmd_execute(num_tokens, tokens);
163 }
164
165
166 int cmd_queue_wait = 0;
167
168 int cmd_queue_process(void)
169 {
170         cmd_queue_t *cmd;
171
172         while (!cmd_queue_wait && cmd_queue_head) {
173                 cmd = cmd_queue_head;
174                 cmd_queue_head = cmd_queue_head->next;
175                 if (!cmd_queue_head)
176                         cmd_queue_tail = NULL;
177
178                 con_printf(CON_DEBUG, "cmd_queue_process: processing %s\n", cmd->command_line);
179                 cmd_parse(cmd->command_line);  // Note, this may change the queue
180
181                 d_free(cmd->command_line);
182                 d_free(cmd);
183         }
184
185         if (cmd_queue_wait > 0) {
186                 cmd_queue_wait--;
187                 if (Function_mode == FMODE_GAME) {
188                         con_printf(CON_DEBUG, "cmd_queue_process: waiting\n");
189                         return 1;
190                 }
191         }
192
193         return 0;
194 }
195
196
197 /* execute until there are no commands left */
198 void cmd_queue_flush(void)
199 {
200         while (cmd_queue_process()) {
201         }
202 }
203
204
205 /* Add some commands to the queue to be executed */
206 void cmd_enqueue(int insert, char *input)
207 {
208         cmd_queue_t *new, *head, *tail;
209         char output[CMD_MAX_LENGTH];
210         char *optr;
211
212         Assert(input != NULL);
213         head = tail = NULL;
214
215         while (*input) {
216                 optr = output;
217                 int quoted = 0;
218
219                 /* Strip leading spaces */
220                 while(isspace(*input) || *input == ';')
221                         input++;
222
223                 /* If command is empty, give up */
224                 if (! *input)
225                         continue;
226
227                 /* Find the end of this line (\n, ;, or nul) */
228                 do {
229                         if (!*input)
230                                 break;
231                         if (*input == '"') {
232                                 quoted = 1 - quoted;
233                                 continue;
234                         } else if ( *input == '\n' || (!quoted && *input == ';') ) {
235                                 input++;
236                                 break;
237                         }
238                 } while ((*optr++ = *input++));
239                 *optr = 0;
240
241                 /* make a new queue item, add it to list */
242                 MALLOC(new, cmd_queue_t, 1);
243                 new->command_line = d_strdup(output);
244                 new->next = NULL;
245
246                 if (!head)
247                         head = new;
248                 if (tail)
249                         tail->next = new;
250                 tail = new;
251
252                 con_printf(CON_DEBUG, "cmd_enqueue: adding %s\n", output);
253         }
254
255         if (insert) {
256                  /* add our list to the head of the main list */
257                 if (cmd_queue_head)
258                         tail->next = cmd_queue_head;
259                 if (!cmd_queue_tail)
260                         cmd_queue_tail = tail;
261                 
262                 cmd_queue_head = head;
263                 con_printf(CON_DEBUG, "cmd_enqueue: added to front of list\n");
264         } else {
265                 /* add our list to the tail of the main list */
266                 if (!cmd_queue_head)
267                         cmd_queue_head = head;
268                 if (cmd_queue_tail)
269                         cmd_queue_tail->next = head;
270                 
271                 cmd_queue_tail = tail;
272                 con_printf(CON_DEBUG, "cmd_enqueue: added to back of list\n");
273         }
274 }
275
276 void cmd_enqueuef(int insert, char *fmt, ...)
277 {
278         va_list arglist;
279         char buf[CMD_MAX_LENGTH];
280         
281         va_start (arglist, fmt);
282         vsnprintf (buf, CMD_MAX_LENGTH, fmt, arglist);
283         va_end (arglist);
284         
285         cmd_enqueue(insert, buf);
286 }
287
288
289 /* Attempt to autocomplete an input string */
290 char *cmd_complete(char *input)
291 {
292         cmd_t *ptr;
293         cmd_alias_t *aptr;
294
295         int len = (int)strlen(input);
296
297         if (!len)
298                 return NULL;
299
300         for (ptr = cmd_list; ptr != NULL; ptr = ptr->next)
301                 if (!strnicmp(input, ptr->name, len))
302                         return ptr->name;
303
304         for (aptr = cmd_alias_list; aptr != NULL; aptr = aptr->next)
305                 if (!strnicmp(input, aptr->name, len))
306                         return aptr->name;
307
308         return cvar_complete(input);
309 }
310
311
312 /* alias */
313 void cmd_alias(int argc, char **argv)
314 {
315         cmd_alias_t *alias;
316         char buf[CMD_MAX_LENGTH] = "";
317         int i;
318
319         if (argc == 2 && !stricmp(argv[1], "-h")) {
320                 con_printf(CON_NORMAL, "%s <name> <commands>\n", argv[0]);
321                 con_printf(CON_NORMAL, "    define <name> as an alias for <commands>\n");
322                 con_printf(CON_NORMAL, "%s <name>\n", argv[0]);
323                 con_printf(CON_NORMAL, "    show the current definition of <name>\n");
324                 con_printf(CON_NORMAL, "%s\n", argv[0]);
325                 con_printf(CON_NORMAL, "    show all defined aliases\n");
326                 return;
327         }
328
329         if (argc < 2) {
330                 con_printf(CON_NORMAL, "aliases:\n");
331                 for (alias = cmd_alias_list; alias; alias = alias->next)
332                         con_printf(CON_NORMAL, "%s: %s\n", alias->name, alias->value);
333                 return;
334         }
335
336         if (argc == 2) {
337                 for (alias = cmd_alias_list; alias; alias = alias->next)
338                         if (!stricmp(argv[1], alias->name)) {
339                                 con_printf(CON_NORMAL, "%s: %s\n", alias->name, alias->value);
340                                 return;
341                         }
342
343                 con_printf(CON_NORMAL, "alias: %s not found\n", argv[1]);
344                 return;
345         }
346
347         for (i = 2; i < argc; i++) {
348                 if (i > 2)
349                         strncat(buf, " ", CMD_MAX_LENGTH);
350                 strncat(buf, argv[i], CMD_MAX_LENGTH);
351         }
352
353         for (alias = cmd_alias_list; alias; alias = alias->next) {
354                 if (!stricmp(argv[1], alias->name)) {
355                         d_free(alias->value);
356                         alias->value = d_strdup(buf);
357                         return;
358                 }
359         }
360
361         MALLOC(alias, cmd_alias_t, 1);
362         strncpy(alias->name, argv[1], ALIAS_NAME_MAX);
363         alias->value = d_strdup(buf);
364         alias->next = cmd_alias_list;
365         cmd_alias_list = alias;
366 }
367
368
369 /* unalias */
370 void cmd_unalias(int argc, char **argv)
371 {
372         cmd_alias_t *alias, *prev_alias = NULL;
373
374         if (argc != 2 || (argc == 2 && !stricmp(argv[1], "-h"))) {
375                 con_printf(CON_NORMAL, "%s <name>\n", argv[0]);
376                 con_printf(CON_NORMAL, "    undefine the alias <name>\n");
377                 return;
378         }
379
380         for (alias = cmd_alias_list; alias ; alias = alias->next) {
381                 if (!stricmp(argv[1], alias->name))
382                         break;
383                 prev_alias = alias;
384         }
385
386         if (!alias) {
387                 con_printf(CON_NORMAL, "alias: %s not found\n", argv[1]);
388                 return;
389         }
390
391         if (prev_alias)
392                 prev_alias->next = alias->next;
393         else
394                 cmd_alias_list = alias->next;
395
396         d_free(alias->value);
397         d_free(alias);
398 }
399
400
401 /* echo to console */
402 void cmd_echo(int argc, char **argv)
403 {
404         char buf[CMD_MAX_LENGTH] = "";
405         int i;
406
407         if (argc == 2 && !stricmp(argv[1], "-h")) {
408                 con_printf(CON_NORMAL, "usage: %s [text]\n", argv[0]);
409                 con_printf(CON_NORMAL, "    write <text> to the console\n");
410
411                 return;
412         }
413
414         for (i = 1; i < argc; i++) {
415                 if (i > 1)
416                         strncat(buf, " ", CMD_MAX_LENGTH);
417                 strncat(buf, argv[i], CMD_MAX_LENGTH);
418         }
419         con_printf(CON_NORMAL, "%s\n", buf);
420 }
421
422 /* execute script */
423 void cmd_exec(int argc, char **argv) {
424         cmd_queue_t *new, *head, *tail;
425         PHYSFS_File *f;
426         char line[CMD_MAX_LENGTH] = "";
427
428         if (argc != 2 || (argc == 2 && !stricmp(argv[1], "-h"))) {
429                 con_printf(CON_NORMAL, "usage: %s <file>\n", argv[0]);
430                 con_printf(CON_NORMAL, "    execute <file>\n");
431
432                 return;
433         }
434
435         head = tail = NULL;
436
437         f = PHYSFSX_openReadBuffered(argv[1]);
438         if (!f) {
439                 con_printf(CON_CRITICAL, "exec: %s not found\n", argv[1]);
440                 return;
441         }
442         while (PHYSFSX_gets(f, line)) {
443                 /* make a new queue item, add it to list */
444                 MALLOC(new, cmd_queue_t, 1);
445                 new->command_line = d_strdup(line);
446                 new->next = NULL;
447
448                 if (!head)
449                         head = new;
450                 if (tail)
451                         tail->next = new;
452                 tail = new;
453
454                 con_printf(CON_DEBUG, "cmd_exec: adding %s\n", line);
455         }
456         PHYSFS_close(f);
457
458         /* add our list to the head of the main list */
459         if (cmd_queue_head)
460                 tail->next = cmd_queue_head;
461         if (!cmd_queue_tail)
462                 cmd_queue_tail = tail;
463
464         cmd_queue_head = head;
465         con_printf(CON_DEBUG, "cmd_exec: added to front of list\n");
466 }
467
468
469 /* get help */
470 void cmd_help(int argc, char **argv)
471 {
472         cmd_t *cmd;
473
474         if (argc > 2 || (argc == 2 && !stricmp(argv[1], "-h"))) {
475                 con_printf(CON_NORMAL, "usage: %s [command]\n", argv[0]);
476                 con_printf(CON_NORMAL, "    get help for <command>, or list all commands if not specified.\n");
477
478                 return;
479         }
480
481         if (argc < 2) {
482                 con_printf(CON_NORMAL, "Available commands:\n");
483                 for (cmd = cmd_list; cmd; cmd = cmd->next) {
484                         con_printf(CON_NORMAL, "    %s\n", cmd->name);
485                 }
486
487                 return;
488         }
489
490         cmd_insertf("%s -h", argv[1]);
491 }
492
493
494 /* execute script */
495 void cmd_wait(int argc, char **argv)
496 {
497         if (argc > 2 || (argc == 2 && !stricmp(argv[1], "-h"))) {
498                 con_printf(CON_NORMAL, "usage: %s [n]\n", argv[0]);
499                 con_printf(CON_NORMAL, "    stop processing commands, resume in <n> cycles (default 1)\n");
500
501                 return;
502         }
503
504         if (argc < 2)
505                 cmd_queue_wait = 1;
506         else
507                 cmd_queue_wait = atoi(argv[1]);
508 }
509
510
511 void cmd_free(void)
512 {
513         void *p, *temp;
514
515         p = cmd_list;
516         while (p) {
517                 temp = p;
518                 p = ((cmd_t *)p)->next;
519                 d_free(temp);
520         }
521
522         p = cmd_alias_list;
523         while (p) {
524                 d_free(((cmd_alias_t *)p)->value);
525                 temp = p;
526                 p = ((cmd_alias_t *)p)->next;
527                 d_free(temp);
528         }
529 }
530
531
532 void cmd_init(void)
533 {
534         cmd_addcommand("alias", cmd_alias);
535         cmd_addcommand("unalias", cmd_unalias);
536         cmd_addcommand("echo", cmd_echo);
537         cmd_addcommand("exec", cmd_exec);
538         cmd_addcommand("help", cmd_help);
539         cmd_addcommand("wait", cmd_wait);
540
541         atexit(cmd_free);
542 }