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