1 //----------------------------------------------------------------------------
2 // EDGE Console Main
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2009 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18
19 #include "i_defs.h"
20
21 #include "epi/filesystem.h"
22 #include "epi/math_crc.h"
23
24 #include "ddf/language.h"
25 #include "ddf/sfx.h"
26
27 #include "con_main.h"
28 #include "con_var.h"
29
30 #include "e_input.h"
31 #include "g_game.h"
32 #include "m_menu.h"
33 #include "m_misc.h"
34 #include "s_sound.h"
35 #include "w_wad.h"
36 #include "version.h"
37 #include "z_zone.h"
38
39
40 #define MAX_CON_ARGS 64
41
42
43 typedef struct
44 {
45 const char *name;
46
47 int (* func)(char **argv, int argc);
48 }
49 con_cmd_t;
50
51
52 // forward decl.
53 extern const con_cmd_t builtin_commands[];
54
55 extern void M_ChangeLevelCheat(const char *string);
56 extern void I_ShowJoysticks(void);
57 extern void M_QuitFinally(void);
58
59
CMD_Exec(char ** argv,int argc)60 int CMD_Exec(char **argv, int argc)
61 {
62 if (argc != 2)
63 {
64 CON_Printf("Usage: exec <script.cfg>\n");
65 return 1;
66 }
67
68 FILE *script = fopen(argv[1], "rb");
69 if (!script)
70 {
71 CON_Printf("Unable to open file: %s\n", argv[1]);
72 return 1;
73 }
74
75 char buffer[200];
76
77 while (fgets(buffer, sizeof(buffer)-1, script))
78 {
79 CON_TryCommand(buffer);
80 }
81
82 fclose(script);
83 return 0;
84 }
85
CMD_Type(char ** argv,int argc)86 int CMD_Type(char **argv, int argc)
87 {
88 FILE *script;
89 char buffer[200];
90
91 if (argc != 2)
92 {
93 CON_Printf("Usage: type <filename.txt>\n");
94 return 2;
95 }
96
97 script = fopen(argv[1], "r");
98 if (!script)
99 {
100 CON_Printf("Unable to open \'%s\'!\n", argv[1]);
101 return 3;
102 }
103 while (fgets(buffer, sizeof(buffer)-1, script))
104 {
105 CON_Printf("%s", buffer);
106 }
107 fclose(script);
108
109 return 0;
110 }
111
CMD_Dir(char ** argv,int argc)112 int CMD_Dir(char **argv, int argc)
113 {
114 const char *path = ".";
115 const char *mask = "*.*";
116
117 if (argc >= 2)
118 path = argv[1];
119
120 if (argc >= 3)
121 mask = argv[2];
122
123 I_Printf("Directory contents matching %s\n", mask);
124
125 epi::filesystem_dir_c fsd;
126
127 if (! FS_ReadDir(&fsd, path, mask))
128 {
129 I_Printf("Failed to read dir: %s\n", path);
130 return 1;
131 }
132
133 for (int i = 0; i < fsd.GetSize(); i++)
134 {
135 epi::filesys_direntry_c *entry = fsd[i];
136
137 I_Printf(" %2d: %10d %s '%s'\n",
138 i+1, entry->size,
139 entry->is_dir ? "DIR" : " ",
140 entry->name.c_str());
141 }
142
143 return 0;
144 }
145
CMD_ArgList(char ** argv,int argc)146 int CMD_ArgList(char **argv, int argc)
147 {
148 I_Printf("Arguments:\n");
149
150 for (int i = 0; i < argc; i++)
151 I_Printf(" %2d len:%d text:\"%s\"\n", i, (int)strlen(argv[i]), argv[i]);
152
153 return 0;
154 }
155
CMD_ScreenShot(char ** argv,int argc)156 int CMD_ScreenShot(char **argv, int argc)
157 {
158 G_DeferredScreenShot();
159
160 return 0;
161 }
162
CMD_QuitEDGE(char ** argv,int argc)163 int CMD_QuitEDGE(char **argv, int argc)
164 {
165 #if 0
166 if (argc >= 2 && stricmp(argv[1], "now") == 0)
167 {
168 // this never returns
169 M_QuitFinally();
170 }
171 #endif
172 M_QuitEDGE(0);
173
174 return 0;
175 }
176
177
CMD_Crc(char ** argv,int argc)178 int CMD_Crc(char **argv, int argc)
179 {
180 int lump, length;
181 const byte *data;
182
183 if (argc < 2)
184 {
185 CON_Printf("Usage: crc <lump>\n");
186 return 1;
187 }
188
189 for (int i = 1; i < argc; i++)
190 {
191 lump = W_CheckNumForName(argv[i]);
192
193 if (lump == -1)
194 {
195 CON_Printf("No such lump: %s\n", argv[i]);
196 }
197 else
198 {
199 length = W_LumpLength(lump);
200 data = (const byte*)W_LoadLumpNum(lump);
201
202 epi::crc32_c result;
203
204 result.Reset();
205 result.AddBlock(data, length);
206
207 Z_Free((void*)data);
208
209 CON_Printf(" %s %d bytes crc = %08x\n", argv[i], length, result.crc);
210 }
211 }
212
213 return 0;
214 }
215
CMD_PlaySound(char ** argv,int argc)216 int CMD_PlaySound(char **argv, int argc)
217 {
218 sfx_t *sfx;
219
220 if (argc != 2)
221 {
222 CON_Printf("Usage: playsound <name>\n");
223 return 1;
224 }
225
226 sfx = sfxdefs.GetEffect(argv[1], false);
227 if (! sfx)
228 {
229 CON_Printf("No such sound: %s\n", argv[1]);
230 }
231 else
232 {
233 S_StartFX(sfx, SNCAT_UI);
234 }
235
236 return 0;
237 }
238
CMD_ResetVars(char ** argv,int argc)239 int CMD_ResetVars(char **argv, int argc)
240 {
241 CON_ResetAllVars();
242 M_ResetDefaults(0);
243 return 0;
244 }
245
CMD_ShowFiles(char ** argv,int argc)246 int CMD_ShowFiles(char **argv, int argc)
247 {
248 W_ShowFiles();
249 return 0;
250 }
251
CMD_ShowLumps(char ** argv,int argc)252 int CMD_ShowLumps(char **argv, int argc)
253 {
254 int for_file = -1; // all files
255
256 char *match = NULL;
257
258 if (argc >= 2 && isdigit(argv[1][0]))
259 for_file = atoi(argv[1]);
260
261 if (argc >= 3)
262 {
263 match = argv[2];
264 strupr(match);
265 }
266
267 W_ShowLumps(for_file, match);
268 return 0;
269 }
270
CMD_ShowVars(char ** argv,int argc)271 int CMD_ShowVars(char **argv, int argc)
272 {
273 bool show_defaults = false;
274
275 char *match = NULL;
276
277 if (argc >= 2 && stricmp(argv[1], "-l") == 0)
278 {
279 show_defaults = true;
280 argv++; argc--;
281 }
282
283 if (argc >= 2)
284 match = argv[1];
285
286 I_Printf("Console Variables:\n");
287
288 int total = 0;
289
290 for (int i = 0; all_cvars[i].name; i++)
291 {
292 if (match && *match)
293 if (! strstr(all_cvars[i].name, match))
294 continue;
295
296 cvar_c *var = all_cvars[i].var;
297
298 if (show_defaults)
299 I_Printf(" %-15s \"%s\" (%s)\n", all_cvars[i].name, var->str, all_cvars[i].def_val);
300 else
301 I_Printf(" %-15s \"%s\"\n", all_cvars[i].name, var->str);
302
303 total++;
304 }
305
306 if (total == 0)
307 I_Printf("Nothing matched.\n");
308
309 return 0;
310 }
311
CMD_ShowCmds(char ** argv,int argc)312 int CMD_ShowCmds(char **argv, int argc)
313 {
314 char *match = NULL;
315
316 if (argc >= 2)
317 match = argv[1];
318
319 I_Printf("Console Commands:\n");
320
321 int total = 0;
322
323 for (int i = 0; builtin_commands[i].name; i++)
324 {
325 if (match && *match)
326 if (! strstr(builtin_commands[i].name, match))
327 continue;
328
329 I_Printf(" %-15s\n", builtin_commands[i].name);
330 total++;
331 }
332
333 if (total == 0)
334 I_Printf("Nothing matched.\n");
335
336 return 0;
337 }
338
CMD_ShowKeys(char ** argv,int argc)339 int CMD_ShowKeys(char **argv, int argc)
340 {
341 #if 0 // TODO
342 char *match = NULL;
343
344 if (argc >= 2)
345 match = argv[1];
346
347 I_Printf("Key Bindings:\n");
348
349 int total = 0;
350
351 for (int i = 0; all_binds[i].name; i++)
352 {
353 if (match && *match)
354 if (! strstr(all_binds[i].name, match))
355 continue;
356
357 std::string keylist = all_binds[i].bind->FormatKeyList();
358
359 I_Printf(" %-15s %s\n", all_binds[i].name, keylist.c_str());
360 total++;
361 }
362
363 if (total == 0)
364 I_Printf("Nothing matched.\n");
365 #endif
366 return 0;
367 }
368
CMD_ShowJoysticks(char ** argv,int argc)369 int CMD_ShowJoysticks(char **argv, int argc)
370 {
371 I_ShowJoysticks();
372 return 0;
373 }
374
375
CMD_Help(char ** argv,int argc)376 int CMD_Help(char **argv, int argc)
377 {
378 I_Printf("Welcome to the EDGE Console.\n");
379 I_Printf("\n");
380 I_Printf("Use the 'showcmds' command to list all commands.\n");
381 I_Printf("The 'showvars' command will list all variables.\n");
382 I_Printf("Both of these can take a keyword to match the names with.\n");
383 I_Printf("\n");
384 I_Printf("To show the value of a variable, just type its name.\n");
385 I_Printf("To change it, follow the name with a space and the new value.\n");
386 I_Printf("\n");
387 I_Printf("Press ESC key to close the console.\n");
388 I_Printf("The PGUP and PGDN keys scroll the console up and down.\n");
389 I_Printf("The UP and DOWN arrow keys let you recall previous commands.\n");
390 I_Printf("\n");
391 I_Printf("Have a nice day!\n");
392
393 return 0;
394 }
395
CMD_Version(char ** argv,int argc)396 int CMD_Version(char **argv, int argc)
397 {
398 I_Printf("EDGE v" EDGEVERSTR "\n");
399 return 0;
400 }
401
402
CMD_Map(char ** argv,int argc)403 int CMD_Map(char **argv, int argc)
404 {
405 if (argc <= 1)
406 {
407 CON_Printf("Usage: map <level>\n");
408 return 0;
409 }
410
411 M_ChangeLevelCheat(argv[1]);
412 return 0;
413 }
414
415
416 //----------------------------------------------------------------------------
417
418 // oh lordy....
StrDup(const char * start,int len)419 static char *StrDup(const char *start, int len)
420 {
421 char *buf = new char[len + 2];
422
423 memcpy(buf, start, len);
424 buf[len] = 0;
425
426 return buf;
427 }
428
GetArgs(const char * line,char ** argv,int max_argc)429 static int GetArgs(const char *line, char **argv, int max_argc)
430 {
431 int argc = 0;
432
433 for (;;)
434 {
435 while (isspace(*line))
436 line++;
437
438 if (! *line)
439 break;
440
441 // silent truncation (bad?)
442 if (argc >= max_argc)
443 break;
444
445 const char *start = line;
446
447 if (*line == '"')
448 {
449 start++; line++;
450
451 while (*line && *line != '"')
452 line++;
453 }
454 else
455 {
456 while (*line && !isspace(*line))
457 line++;
458 }
459
460 // ignore empty strings at beginning of the line
461 if (! (argc == 0 && start == line))
462 {
463 argv[argc++] = StrDup(start, line - start);
464 }
465
466 if (*line)
467 line++;
468 }
469
470 return argc;
471 }
472
KillArgs(char ** argv,int argc)473 static void KillArgs(char **argv, int argc)
474 {
475 for (int i = 0; i < argc; i++)
476 delete[] argv[i];
477 }
478
479
480 //
481 // Current console commands:
482 //
483 const con_cmd_t builtin_commands[] =
484 {
485 { "args", CMD_ArgList },
486 { "crc", CMD_Crc },
487 { "dir", CMD_Dir },
488 { "exec", CMD_Exec },
489 { "help", CMD_Help },
490 { "map", CMD_Map },
491 { "warp", CMD_Map }, // compatibility
492 { "playsound", CMD_PlaySound },
493 // { "resetkeys", CMD_ResetKeys },
494 { "resetvars", CMD_ResetVars },
495 { "showfiles", CMD_ShowFiles },
496 { "showjoysticks", CMD_ShowJoysticks },
497 // { "showkeys", CMD_ShowKeys },
498 { "showlumps", CMD_ShowLumps },
499 { "showcmds", CMD_ShowCmds },
500 { "showvars", CMD_ShowVars },
501 { "screenshot", CMD_ScreenShot },
502 { "type", CMD_Type },
503 { "version", CMD_Version },
504 { "quit", CMD_QuitEDGE },
505 { "exit", CMD_QuitEDGE },
506
507 // end of list
508 { NULL, NULL }
509 };
510
511
FindCommand(const char * name)512 static int FindCommand(const char *name)
513 {
514 for (int i = 0; builtin_commands[i].name; i++)
515 {
516 if (stricmp(name, builtin_commands[i].name) == 0)
517 return i;
518 }
519
520 return -1; // not found
521 }
522
523 #if 0
524 static void ProcessBind(key_link_t *link, char **argv, int argc)
525 {
526 for (int i = 1; i < argc; i++)
527 {
528 if (stricmp(argv[i], "-c") == 0)
529 {
530 link->bind->Clear();
531 continue;
532 }
533
534 int keyd = E_KeyFromName(argv[i]);
535 if (keyd == 0)
536 {
537 CON_Printf("Invalid key name: %s\n", argv[i]);
538 continue;
539 }
540
541 link->bind->Toggle(keyd);
542 }
543 }
544 #endif
545
CON_TryCommand(const char * cmd)546 void CON_TryCommand(const char *cmd)
547 {
548 char *argv[MAX_CON_ARGS];
549 int argc = GetArgs(cmd, argv, MAX_CON_ARGS);
550
551 if (argc == 0)
552 return;
553
554 int index = FindCommand(argv[0]);
555 if (index >= 0)
556 {
557 (* builtin_commands[index].func)(argv, argc);
558
559 KillArgs(argv, argc);
560 return;
561 }
562
563 cvar_link_t *link = CON_FindVar(argv[0]);
564 if (link)
565 {
566 if (argc <= 1)
567 I_Printf("%s \"%s\"\n", argv[0], link->var->str);
568 else if (argc >= 3)
569 I_Printf("Can only assign one value (%d given).\n", argc-1);
570 else if (strchr(link->flags, 'r'))
571 I_Printf("That cvar is read only.\n");
572 else
573 *link->var = argv[1];
574
575 KillArgs(argv, argc);
576 return;
577 }
578
579 #if 0
580 // hmmm I like it kinky...
581 key_link_t *kink = E_FindKeyBinding(argv[0]);
582 if (kink)
583 {
584 if (argc <= 1)
585 {
586 std::string keylist = kink->bind->FormatKeyList();
587
588 I_Printf("%s %s\n", argv[0], keylist.c_str());
589 }
590 else
591 {
592 ProcessBind(kink, argv, argc);
593 }
594
595 KillArgs(argv, argc);
596 return;
597 }
598 #endif
599
600 I_Printf("Unknown console command: %s\n", argv[0]);
601
602 KillArgs(argv, argc);
603 return;
604 }
605
606
CON_MatchAllCmds(std::vector<const char * > & list,const char * pattern)607 int CON_MatchAllCmds(std::vector<const char *>& list,
608 const char *pattern)
609 {
610 list.clear();
611
612 for (int i = 0; builtin_commands[i].name; i++)
613 {
614 if (! CON_MatchPattern(builtin_commands[i].name, pattern))
615 continue;
616
617 list.push_back(builtin_commands[i].name);
618 }
619
620 return (int)list.size();
621 }
622
623
624 //
625 // CON_PlayerMessage
626 //
627 // -ACB- 1999/09/22 Console Player Message Only. Changed from
628 // #define to procedure because of compiler
629 // differences.
630 //
CON_PlayerMessage(int plyr,const char * message,...)631 void CON_PlayerMessage(int plyr, const char *message, ...)
632 {
633 va_list argptr;
634 char buffer[256];
635
636 if (consoleplayer != plyr)
637 return;
638
639 Z_Clear(buffer, char, 256);
640
641 va_start(argptr, message);
642 vsprintf(buffer, message, argptr);
643 va_end(argptr);
644
645 CON_Message("%s", buffer);
646 }
647
648 //
649 // CON_PlayerMessageLDF
650 //
651 // -ACB- 1999/09/22 Console Player Message Only. Changed from
652 // #define to procedure because of compiler
653 // differences.
654 //
CON_PlayerMessageLDF(int plyr,const char * lookup,...)655 void CON_PlayerMessageLDF(int plyr, const char *lookup, ...)
656 {
657 va_list argptr;
658 char buffer[256];
659
660 if (consoleplayer != plyr)
661 return;
662
663 lookup = language[lookup];
664
665 Z_Clear(buffer, char, 256);
666
667 va_start(argptr, lookup);
668 vsprintf(buffer, lookup, argptr);
669 va_end(argptr);
670
671 CON_Message("%s", buffer);
672 }
673
674
675 //--- editor settings ---
676 // vi:ts=4:sw=4:noexpandtab
677