]> icculus.org git repositories - btb/d2x.git/blob - main/cmd.c
command queueing
[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 "weapon.h"
17 #include "key.h"
18
19
20 typedef struct cmd_s
21 {
22         char          *name;
23         cmd_handler_t function;
24         struct cmd_s  *next;
25 } cmd_t;
26
27 /* The list of cmds */
28 static cmd_t *cmd_list = NULL;
29
30
31 #define ALIAS_NAME_MAX 32
32 typedef struct cmd_alias_s
33 {
34         char           name[ALIAS_NAME_MAX];
35         char           *value;
36         struct cmd_alias_s *next;
37 } cmd_alias_t;
38
39 /* The list of aliases */
40 static cmd_alias_t *cmd_alias_list = NULL;
41
42
43 /* The list of keybindings */
44 static char *cmd_keybinding_list[256];
45
46
47 /* add a new console command */
48 void cmd_addcommand(char *cmd_name, cmd_handler_t cmd_func)
49 {
50         cmd_t *cmd;
51
52         Assert(cmd_name != NULL);
53
54         for (cmd = cmd_list; cmd; cmd = cmd->next) {
55                 if (!stricmp(cmd_name, cmd->name))
56                 {
57                         Int3();
58                         con_printf(CON_NORMAL, "command %s already exists, not adding\n", cmd_name);
59                         return;
60                 }
61         }
62
63         /* create command, insert at front of list */
64         MALLOC(cmd, cmd_t, 1);
65         cmd->name = cmd_name;
66         cmd->function = cmd_func;
67         cmd->next = cmd_list;
68         cmd_list = cmd;
69 }
70
71
72 typedef struct cmd_queue_s
73 {
74         char *command_line;
75         struct cmd_queue_s *next;
76 } cmd_queue_t;
77
78 /* The list of commands to be executed */
79 static cmd_queue_t *cmd_queue_head = NULL;
80 static cmd_queue_t *cmd_queue_tail = NULL;
81
82
83 /* execute a parsed command */
84 void cmd_execute(int argc, char **argv)
85 {
86         cmd_t *cmd;
87         cmd_alias_t *alias;
88
89         for (cmd = cmd_list; cmd; cmd = cmd->next) {
90                 if (!stricmp(argv[0], cmd->name))
91                         return cmd->function(argc, argv);
92         }
93
94         for (alias = cmd_alias_list; alias; alias = alias->next) {
95                 if (!stricmp(argv[0], alias->name)) {
96                         cmd_insert(alias->value);
97                         cmd_parse(alias->value);
98                         return;
99                 }
100         }
101
102         /* Otherwise */
103         if (argc > 1)  // set value of cvar
104                 cvar_set(argv[0], argv[1]);
105         con_printf(CON_NORMAL, "%s: %f\n", argv[0], cvar(argv[0]));
106 }
107
108
109 /* Parse an input string */
110 void cmd_parse(char *input)
111 {
112         char buffer[CMD_MAX_LENGTH];
113         char *tokens[CMD_MAX_TOKENS];
114         int num_tokens;
115         int i, l;
116         int quoted = 0;
117
118         Assert(input != NULL);
119         
120         /* Strip leading spaces */
121         for (i=0; isspace(input[i]); i++) ;
122         strncpy( buffer, &input[i], CMD_MAX_LENGTH );
123
124         //printf("lead strip \"%s\"\n",buffer);
125         l = strlen(buffer);
126         /* If command is empty, give up */
127         if (l==0) return;
128
129         /* Strip trailing spaces */
130         for (i=l-1; i>0 && isspace(buffer[i]); i--) ;
131         buffer[i+1] = 0;
132         //printf("trail strip \"%s\"\n",buffer);
133
134         /* Split into tokens */
135         l = strlen(buffer);
136         num_tokens = 1;
137
138         tokens[0] = buffer;
139         for (i=1; i<l; i++) {
140                 if (buffer[i] == '"') {
141                         quoted = 1 - quoted;
142                         continue;
143                 }
144                 if (isspace(buffer[i]) && !quoted) {
145                         buffer[i] = 0;
146                         while (isspace(buffer[i+1]) && (i+1 < l)) i++;
147                         tokens[num_tokens++] = &buffer[i+1];
148                 }
149         }
150
151         /* Check for matching commands */
152         cmd_execute(num_tokens, tokens);
153 }
154
155 void cmd_parsef(char *fmt, ...){
156         va_list arglist;
157         char buf[CMD_MAX_LENGTH];
158
159         va_start (arglist, fmt);
160         vsnprintf (buf, CMD_MAX_LENGTH, fmt, arglist);
161         va_end (arglist);
162
163         cmd_parse(buf);
164 }
165
166
167 /* Add some commands to the queue to be executed */
168 void cmd_enqueue(int insert, char *input)
169 {
170         cmd_queue_t *new, *head, *tail;
171         char *line;
172
173         Assert(input != NULL);
174         head = tail = NULL;
175
176         while (*input) {
177                 int quoted = 0;
178
179                 /* Strip leading spaces */
180                 while(isspace(*input) || *input == ';')
181                         input++;
182
183                 /* If command is empty, give up */
184                 if (! *input)
185                         continue;
186
187                 /* Now at start of a command line */
188                 line = input;
189
190                 /* Find the end of this line (\n, ;, or nul) */
191                 do {
192                         if (!*input)
193                                 break;
194                         if (*input == '"') {
195                                 quoted = 1 - quoted;
196                                 continue;
197                         } else if ( *input == '\n' || (!quoted && *input == ';') ) {
198                                 *input = 0;
199                                 break;
200                         }
201                 } while (*input++);
202
203                 printf("enqueue: got line: %s\n", line);
204                 
205                 /* make a new queue item, add it to list */
206                 MALLOC(new, cmd_queue_t, 1);
207                 new->command_line = strdup(line);
208                 new->next = NULL;
209
210                 if (!head)
211                         head = new;
212                 if (tail)
213                         tail->next = new;
214                 tail = new;
215         }
216
217         if (insert) {
218                  /* add our list to the head of the main list */
219                 if (cmd_queue_head)
220                         tail->next = cmd_queue_head;
221                 if (!cmd_queue_tail)
222                         cmd_queue_tail = tail;
223                 
224                 cmd_queue_head = head;
225         } else {
226                 /* add our list to the tail of the main list */
227                 if (!cmd_queue_head)
228                         cmd_queue_head = new;
229                 if (cmd_queue_tail)
230                         cmd_queue_tail->next = head;
231                 
232                 cmd_queue_tail = tail;
233         }
234 }
235
236 void cmd_enqueuef(int insert, char *fmt, ...){
237         va_list arglist;
238         char buf[CMD_MAX_LENGTH];
239         
240         va_start (arglist, fmt);
241         vsnprintf (buf, CMD_MAX_LENGTH, fmt, arglist);
242         va_end (arglist);
243         
244         cmd_enqueue(insert, buf);
245 }
246
247
248 /* Attempt to autocomplete an input string */
249 char *cmd_complete(char *input)
250 {
251         CON_Out("     No autocomplete yet");
252         return NULL;
253 }
254
255
256 int cmd_handle_keybinding(unsigned char key)
257 {
258         if (cmd_keybinding_list[key]) {
259                 cmd_parse(cmd_keybinding_list[key]);
260                 return 1;
261         }
262         return 0;
263 }
264
265
266
267 /* alias */
268 void cmd_alias(int argc, char **argv)
269 {
270         cmd_alias_t *alias;
271         char buf[CMD_MAX_LENGTH] = "";
272         int i;
273
274         if (argc < 2)
275         {
276                 con_printf(CON_NORMAL, "aliases:\n");
277                 for (alias = cmd_alias_list; alias; alias = alias->next)
278                         con_printf(CON_NORMAL, "%s: %s\n", alias->name, alias->value);
279                 return;
280         }
281
282         for (i = 2; i < argc; i++) {
283                 if (i > 2)
284                         strncat(buf, " ", CMD_MAX_LENGTH);
285                 strncat(buf, argv[i], CMD_MAX_LENGTH);
286         }
287
288         for (alias = cmd_alias_list; alias; alias = alias->next) {
289                 if (!stricmp(argv[1], alias->name))
290                 {
291                         d_free(alias->value);
292                         alias->value = d_strdup(buf);
293                         return;
294                 }
295         }
296
297         MALLOC(alias, cmd_alias_t, 1);
298         strncpy(alias->name, argv[1], ALIAS_NAME_MAX);
299         alias->value = d_strdup(buf);
300         alias->next = cmd_alias_list;
301         cmd_alias_list = alias;
302 }
303
304 /* bind */
305 /* FIXME: key_text is not really adequate for this */
306 void cmd_bind(int argc, char **argv)
307 {
308         char buf[CMD_MAX_LENGTH] = "";
309         unsigned char key = 0;
310         int i;
311
312         if (argc < 2)
313         {
314                 con_printf(CON_NORMAL, "key bindings:\n");
315                 for (i = 0; i < 256; i++) {
316                         if (!cmd_keybinding_list[i])
317                                 continue;
318                         con_printf(CON_NORMAL, "%s: %s\n", key_text[i], cmd_keybinding_list[i]);
319                 }
320                 return;
321         }
322
323         for (i = 2; i < argc; i++) {
324                 if (i > 2)
325                         strncat(buf, " ", CMD_MAX_LENGTH);
326                 strncat(buf, argv[i], CMD_MAX_LENGTH);
327         }
328
329         for (i = 0; i < 256; i++) {
330                 if (!stricmp(argv[1], key_text[i])) {
331                         key = i;
332                         break;
333                 }
334         }
335
336         if (!key) {
337                 con_printf(CON_CRITICAL, "bind: key %s not found\n", argv[1]);
338                 return;
339         }
340
341         if (cmd_keybinding_list[key])
342                 d_free(cmd_keybinding_list[key]);
343         cmd_keybinding_list[key] = d_strdup(buf);
344 }
345
346 /* +/- actions */
347 int Console_button_states[CMD_NUM_BUTTONS];
348 void cmd_attack_on(int argc, char **argv) { Console_button_states[CMD_ATTACK] = 1; }
349 void cmd_attack_off(int argc, char **argv) { Console_button_states[CMD_ATTACK] = 0; }
350 void cmd_attack2_on(int argc, char **argv) { Console_button_states[CMD_ATTACK2] = 1; }
351 void cmd_attack2_off(int argc, char **argv) { Console_button_states[CMD_ATTACK2] = 0; }
352
353 /* weapon select */
354 void cmd_impulse(int argc, char**argv) {
355         if (argc < 2)
356                 return;
357         int n = atoi(argv[1]);
358         if (n >= 1 && n <= 20) {
359                 select_weapon((n-1) % 10, (n-1) / 10, 0, 1);
360         }
361 }
362
363 /* echo to console */
364 void cmd_echo(int argc, char **argv) {
365         char buf[CMD_MAX_LENGTH] = "";
366         int i;
367         for (i = 1; i < argc; i++) {
368                 if (i > 1)
369                         strncat(buf, " ", CMD_MAX_LENGTH);
370                 strncat(buf, argv[i], CMD_MAX_LENGTH);
371         }
372         con_printf(CON_NORMAL, "%s\n", buf);
373 }
374
375 /* execute script */
376 void cmd_exec(int argc, char **argv) {
377         PHYSFS_File *f;
378         char buf[CMD_MAX_LENGTH] = "";
379
380         if (argc < 2)
381                 return;
382         f = PHYSFSX_openReadBuffered(argv[1]);
383         if (!f) {
384                 con_printf(CON_CRITICAL, "exec: %s not found\n", argv[1]);
385                 return;
386         }
387         while (PHYSFSX_gets(f, buf)) {
388                 cmd_append(buf);
389                 cmd_parse(buf);
390         }
391         PHYSFS_close(f);
392 }
393
394
395 void cmd_free(void)
396 {
397         int i;
398         void *p, *temp;
399
400         p = cmd_list;
401         while (p) {
402                 temp = p;
403                 p = ((cmd_t *)p)->next;
404                 d_free(temp);
405         }
406
407         p = cmd_alias_list;
408         while (p) {
409                 d_free(((cmd_alias_t *)p)->value);
410                 temp = p;
411                 p = ((cmd_alias_t *)p)->next;
412                 d_free(temp);
413         }
414
415         for (i = 0; i < 256; i++)
416                 if (cmd_keybinding_list[i])
417                         d_free(cmd_keybinding_list[i]);
418 }
419
420
421 void cmd_init(void){
422         memset(Console_button_states, 0, sizeof(int) * CMD_NUM_BUTTONS);
423
424         cmd_addcommand("alias", cmd_alias);
425         cmd_addcommand("bind", cmd_bind);
426
427         cmd_addcommand("+attack", cmd_attack_on);
428         cmd_addcommand("-attack", cmd_attack_off);
429         cmd_addcommand("+attack2", cmd_attack2_on);
430         cmd_addcommand("-attack2", cmd_attack2_off);
431
432         cmd_addcommand("impulse", cmd_impulse);
433
434         cmd_addcommand("echo", cmd_echo);
435
436         cmd_addcommand("exec", cmd_exec);
437
438         atexit(cmd_free);
439 }