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