2 * $Logfile: /Freespace2/code/DebugConsole/Console.cpp $
7 * Routines for managing the debug console window.
10 * Revision 1.1 2002/05/03 03:28:08 root
14 * 4 6/04/99 10:35a Dave
16 * 3 10/13/98 9:28a Dave
17 * Started neatening up freespace.h. Many variables renamed and
18 * reorganized. Added AlphaColors.[h,cpp]
20 * 2 10/07/98 10:52a Dave
23 * 1 10/07/98 10:48a Dave
25 * 17 2/05/98 11:43a Allender
26 * enhcanced network statistic collection. Made callback in debug console
27 * to do networking if player is in the console
29 * 16 1/22/98 6:42p John
30 * Move game_flush out of debug console into freespace. Made object
31 * pair code throw out some weapons that turn. Added stats for how many
32 * object pair are actually checked.
34 * 15 1/16/98 11:56a Allender
35 * ability to scroll back in debug console, and call game_flush() when
38 * 14 1/10/98 1:14p John
39 * Added explanation to debug console commands
41 * 13 12/21/97 4:39p John
42 * fixed bug in name compare
44 * 12 12/21/97 4:33p John
45 * Made debug console functions a class that registers itself
46 * automatically, so you don't need to add the function to
49 * 11 9/13/97 9:31a Lawrance
50 * if playing a demo, clear key filter then reset it once done with debug
53 * 10 9/09/97 3:39p Sandeep
54 * warning level 4 bugs
56 * 9 6/13/97 3:50p John
57 * sped up debug console printf
59 * 8 6/13/97 3:27p John
60 * made debug console pretty
62 * 7 6/09/97 9:24a John
63 * Changed the way fonts are set.
65 * 6 5/29/97 3:09p John
66 * Took out debug menu.
67 * Made software scaler draw larger bitmaps.
68 * Optimized Direct3D some.
70 * 5 5/13/97 4:07p John
71 * made numbers also be marked as strings.
73 * 4 4/28/97 5:24p John
74 * made so : and \ don't get parsed out in debug console.
76 * 3 4/24/97 11:49a John
77 * added new lighting commands to console.
79 * 2 4/24/97 10:36a John
80 * moved the debug console stuff into it's own lib... made it compile with
83 * 1 4/24/97 10:16a John
96 #include "freespace.h"
101 #include "alphacolors.h"
104 #define MAX_COMMANDS 300
106 static int Num_debug_commands = 0;
107 static debug_command *Debug_command[MAX_COMMANDS];
110 debug_command::debug_command(char *_name, char *_help, void (*_func)() )
114 if ( Num_debug_commands >= MAX_COMMANDS ) {
115 Int3(); // Too many debug console commands!! Increase MAX_COMMANDS!!
119 for (i=0; i<Num_debug_commands; i++ ) {
120 int ret = stricmp( Debug_command[i]->name, _name );
123 Int3(); // This debug console command already exists!!!!
125 } else if ( ret > 0 ) {
126 break; // Insert it here
128 } else if ( ret < 0 ) {
133 if ( i < Num_debug_commands ) {
134 // Insert it at element i
136 for (j=Num_debug_commands; j>i; j-- ) {
137 Debug_command[j] = Debug_command[j-1];
139 Debug_command[i] = this;
140 Num_debug_commands++;
142 Debug_command[Num_debug_commands] = this;
143 Num_debug_commands++;
151 // some global variables
152 int Dc_command; // If this is set, then process the command
153 int Dc_help; // If this is set, then print out the help text in the form, "usage: ... \nLong description\n" );
154 int Dc_status; // If this is set, then print out the current status of the command.
155 char *Dc_arg; // The (lowercased) string value of the argument retrieved from dc_arg
156 char *Dc_arg_org; // Dc_arg before it got converted to lowercase
157 uint Dc_arg_type; // The type of dc_arg.
158 char *Dc_command_line; // The rest of the command line, from the end of the last processed arg on.
159 int Dc_arg_int; // If Dc_arg_type & ARG_INT is set, then this is the value
160 float Dc_arg_float; // If Dc_arg_type & ARG_FLOAT is set, then this is the value
162 int scroll_times = 0; // incremented each time display scrolls
164 int debug_inited = 0;
169 int debug_x=0, debug_y=0;
170 char debug_text[DROWS][DCOLS];
173 static char command_line[1024];
174 static int command_line_pos = 0;
175 #define DEBUG_HISTORY 16
176 static char oldcommand_line[DEBUG_HISTORY][1024];
177 int last_oldcommand=-1;
178 int command_scroll = 0;
180 ///=========================== SCANNER =======================
182 LETTER, QUOTE, SPECIAL, EOF_CODE, DIGIT,
186 NO_TOKEN, IDENTIFIER, NUMBER, STRING,
190 #define MAX_TOKEN_STRING_LENGTH 128
193 TOKEN_CODE scanner_token;
195 char scanner_token_string[MAX_TOKEN_STRING_LENGTH];
196 char scanner_word_string[MAX_TOKEN_STRING_LENGTH];
197 char * scanner_bufferp = "";
198 char * scanner_tokenp = scanner_token_string;
200 CHAR_CODE scanner_char_table[256];
202 #define scanner_char_code(x) scanner_char_table[x]
204 void scanner_get_char()
206 if ( *scanner_bufferp == '\0' ) {
210 scanner_ch = *scanner_bufferp++;
216 for (ch=0; ch<256; ++ch) scanner_char_table[ch] = SPECIAL;
217 for (ch='0'; ch<='9'; ++ch) scanner_char_table[ch] = DIGIT;
218 for (ch='A'; ch<='Z'; ++ch) scanner_char_table[ch] = LETTER;
219 for (ch='a'; ch<='z'; ++ch) scanner_char_table[ch] = LETTER;
221 scanner_char_table['.'] = DIGIT;
222 scanner_char_table['-'] = DIGIT;
223 scanner_char_table['+'] = DIGIT;
225 scanner_char_table['_'] = LETTER;
226 scanner_char_table[34] = QUOTE;
227 scanner_char_table[0] = EOF_CODE;
230 scanner_char_table[':'] = LETTER;
231 scanner_char_table['\\'] = LETTER;
237 void scanner_skip_blanks()
239 while( (scanner_ch ==' ') || (scanner_ch =='\t') )
244 void scanner_downshift_word()
246 int offset = 'a' - 'A';
249 strcpy( scanner_word_string, scanner_token_string );
251 tp = scanner_word_string;
253 *tp = (char)((*tp>='A') && (*tp <='Z') ? *tp + offset : *tp) ;
255 } while (*tp != '\0' );
259 void scanner_get_word()
261 while( (scanner_char_code(scanner_ch)==LETTER) || (scanner_char_code(scanner_ch)==DIGIT) ) {
262 *scanner_tokenp++ = scanner_ch;
265 *scanner_tokenp = '\0';
267 scanner_token = IDENTIFIER;
271 void scanner_get_string()
273 *scanner_tokenp++ = 34;
276 while(scanner_ch != 34 ) {
277 *scanner_tokenp++ = scanner_ch;
281 *scanner_tokenp++ = 34;
282 *scanner_tokenp = '\0';
283 scanner_token = STRING;
288 void scanner_get_token()
290 scanner_skip_blanks();
291 scanner_tokenp = scanner_token_string;
295 switch( scanner_char_code(scanner_ch) ) {
296 case QUOTE: scanner_get_string(); break;
297 case EOF_CODE: scanner_token = NO_TOKEN; break;
299 case LETTER: scanner_get_word(); break;
301 *scanner_tokenp++ = scanner_ch;
302 *scanner_tokenp = '\0';
304 scanner_token = IDENTIFIER;
308 scanner_downshift_word();
311 void scanner_start_command( char * s )
321 void dc_get_arg(uint type)
325 Dc_command_line = scanner_bufferp;
326 Dc_arg_org = scanner_token_string;
327 Dc_arg = scanner_word_string;
330 dc_printf( "next arg is '%s', was originally '%s'\n", Dc_arg, Dc_arg_org );
331 dc_printf( "Rest of the command line is '%s'\n", Dc_command_line );
334 if ( scanner_token == NO_TOKEN ) {
335 Dc_arg_type = ARG_NONE;
336 } else if ( scanner_token == IDENTIFIER ) {
337 Dc_arg_type = ARG_STRING;
338 } else if ( scanner_token == STRING ) {
339 Dc_arg_type = ARG_QUOTE;
341 Dc_arg_type = ARG_STRING;
344 if ( Dc_arg_type & ARG_STRING ) {
345 int i, num_digits, len;
347 len = strlen(Dc_arg);
350 for (i=0; i<len; i++)
351 if ( scanner_char_table[Dc_arg[i]] == DIGIT ) num_digits++;
353 if ( num_digits==len ) {
354 Dc_arg_type |= ARG_FLOAT;
355 Dc_arg_float = (float)atof(Dc_arg);
356 if ( !strchr( Dc_arg, '.' )) {
357 Dc_arg_type |= ARG_INT;
358 Dc_arg_int = atoi(Dc_arg);
361 if ( (Dc_arg[0] == '0') && (Dc_arg[1] == 'x') ) {
364 n = strtol(Dc_arg,&p,0);
366 Dc_arg_type |= ARG_INT|ARG_HEX;
373 if ( Dc_arg_type & ARG_FLOAT )
374 dc_printf( "Found float number! %f\n", Dc_arg_float );
376 if ( Dc_arg_type & ARG_INT )
377 dc_printf( "Found int number! %d\n", Dc_arg_int );
379 if ( Dc_arg_type & ARG_HEX )
380 dc_printf( "Found hex number! 0x%x\n", Dc_arg_int );
383 if ( !stricmp( Dc_arg, "on" ))
384 Dc_arg_type |= ARG_TRUE;
385 if ( !stricmp( Dc_arg, "true" ))
386 Dc_arg_type |= ARG_TRUE;
387 if ( !stricmp( Dc_arg, "off" ))
388 Dc_arg_type |= ARG_FALSE;
389 if ( !stricmp( Dc_arg, "false" ))
390 Dc_arg_type |= ARG_FALSE;
392 if ( !stricmp( Dc_arg, "+" ))
393 Dc_arg_type |= ARG_PLUS;
395 if ( !stricmp( Dc_arg, "-" ))
396 Dc_arg_type |= ARG_MINUS;
398 if ( !stricmp( Dc_arg, "," ))
399 Dc_arg_type |= ARG_COMMA;
402 if ( Dc_arg_type & ARG_INT) {
404 Dc_arg_type |= ARG_TRUE;
406 Dc_arg_type |= ARG_FALSE;
409 if ( !(Dc_arg_type&type) ) {
410 if ( (Dc_arg_type & ARG_NONE) && !(type & ARG_NONE))
411 dc_printf( "Error: Not enough parameters.\n" );
413 dc_printf( "Error: '%s' invalid type\n", Dc_arg );
414 longjmp(dc_bad_arg,1);
421 void debug_do_command(char * command)
427 if ( strlen(command) < 1 ) return;
430 Dc_command_line = command;
431 scanner_start_command(command);
433 if (setjmp(dc_bad_arg) ) {
437 dc_get_arg( ARG_ANY );
439 if ( !strcmp( Dc_arg, "debug" ) ) {
441 dc_printf( "Command line: '%s'\n", Dc_command_line );
442 dc_get_arg( ARG_ANY );
445 if ( !strcmp( Dc_arg, "?" ) ) {
447 dc_get_arg( ARG_ANY );
449 if ( Dc_arg_type&ARG_NONE ) {
455 if ( !strcmp( Dc_arg, "help" ) || !strcmp( Dc_arg, "man" ) ) {
457 dc_get_arg( ARG_ANY );
458 if ( Dc_arg_type&ARG_NONE ) {
464 if ( strstr( Dc_command_line, "?" ) ) {
468 if ( !(Dc_arg_type&ARG_STRING) ) {
469 dc_printf( "Invalid keyword '%s'\n", Dc_arg );
475 dc_printf( "Searching for command '%s'\n", Dc_arg );
478 for (i=0; i<Num_debug_commands; i++ ) {
479 if ( !stricmp( Debug_command[i]->name, Dc_arg )) {
483 dc_printf( "Calling function '%s'\n", Dc_arg );
487 } else if (mode==1) {
489 dc_printf( "Checking status for '%s'\n", Dc_arg );
495 dc_printf( "Doing help for '%s'\n", Dc_arg );
501 (*Debug_command[i]->func)();
505 if (!(Dc_arg_type&ARG_NONE)) {
506 dc_printf( "Ignoring the unused command line tail '%s %s'\n", Dc_arg_org, Dc_command_line );
514 dc_printf( "Unknown command '%s'\n", Dc_arg );
523 gr_set_color_fast( &Color_bright );
524 gr_string( 0x8000, 3, "Debug Console" );
526 gr_set_color_fast( &Color_normal );
528 for (i=0; i<DROWS; i++ ) {
529 gr_string( 0, i*16+16, debug_text[i] );
532 int t = timer_get_fixed_seconds() / (F1_0/3);
537 c = debug_text[debug_y][command_line_pos+1];
538 debug_text[debug_y][command_line_pos+1] = 0;
540 gr_get_string_size( &w, &h, debug_text[debug_y] );
542 //gr_string( w, debug_y*16, "_" );
543 gr_rect(w+1,debug_y*16+1+16,2,14);
545 debug_text[debug_y][command_line_pos+1] = c;
552 void debug_output( char c )
555 int next_tab = ((debug_x/28)+1)*28;
557 if ( next_tab >= DCOLS-1 ) {
561 if ( debug_y >= DROWS ) {
563 for (i=1; i<DROWS; i++ )
564 strcpy( debug_text[i-1], debug_text[i] );
567 debug_text[debug_y][debug_x] = 0;
569 debug_text[debug_y][debug_x] = 0;
573 for ( ; debug_x < next_tab; )
574 debug_text[debug_y][debug_x++] = ' ';
575 debug_text[debug_y][debug_x] = 0;
579 if ( (c == '\n') || (debug_x >= DCOLS-1) ) {
583 if ( debug_y >= DROWS ) {
585 for (i=1; i<DROWS; i++ )
586 strcpy( debug_text[i-1], debug_text[i] );
589 debug_text[debug_y][debug_x] = 0;
591 debug_text[debug_y][debug_x] = 0;
592 if ( c == '\n' ) return;
595 debug_text[debug_y][debug_x++] = c;
596 debug_text[debug_y][debug_x] = 0;
599 void dc_printf(char *format, ...)
604 va_start(args, format);
605 vsprintf(tmp, format, args);
620 if ( debug_inited ) return;
627 for (i=0; i<DROWS; i++ ) {
628 debug_text[i][0] = 0;
631 dc_printf("Debug console started.\n" );
635 void debug_console( void (*_func)() )
641 while( key_inkey() ){
645 if ( !debug_inited ) debug_init();
657 case KEY_SHIFTED+KEY_ENTER:
662 if ( command_line_pos > 0 ) {
663 command_line[--command_line_pos] = 0;
668 if ( last_oldcommand > -1 ) {
669 strcpy( command_line, oldcommand_line[last_oldcommand] );
670 command_line_pos = strlen(command_line);
671 command_line[command_line_pos] = 0;
677 if (command_scroll<0)
678 command_scroll = last_oldcommand;
680 if ( command_scroll > -1 ) {
681 strcpy( command_line, oldcommand_line[command_scroll] );
682 command_line_pos = strlen(command_line);
683 command_line[command_line_pos] = 0;
689 if (command_scroll>last_oldcommand)
691 if (command_scroll>last_oldcommand)
693 if ( command_scroll > -1 ) {
694 strcpy( command_line, oldcommand_line[command_scroll] );
695 command_line_pos = strlen(command_line);
696 command_line[command_line_pos] = 0;
701 debug_output( '\n' );
704 debug_do_command(command_line);
707 for (i=0; i<=last_oldcommand; i++ ) {
708 if (!stricmp( oldcommand_line[i], command_line )) {
713 if ( last_oldcommand < DEBUG_HISTORY-1 ) {
715 strcpy( oldcommand_line[last_oldcommand], command_line);
718 for (i=0; i<last_oldcommand; i++ ) {
719 strcpy( oldcommand_line[i], oldcommand_line[i+1] );
721 strcpy( oldcommand_line[last_oldcommand], command_line);
725 // for (i=0; i<=last_oldcommand; i++ ) {
726 // dc_printf( "OC %d. %s\n", i, oldcommand_line[i] );
729 debug_output( '\n' );
730 command_line_pos = 0;
731 command_line[command_line_pos] = 0;
738 ubyte c = (ubyte)key_to_ascii(k);
740 command_line[command_line_pos++] = c;
741 command_line[command_line_pos] = 0;
746 strcpy( debug_text[debug_y], ">" );
747 strcat( debug_text[debug_y], command_line );
755 while( key_inkey() ){
764 dc_printf( "Available functions:\n\n" );
767 for (i=0; i<Num_debug_commands; i++ ) {
768 dc_printf( " %s - %s\n", Debug_command[i]->name, Debug_command[i]->help );
769 //mprintf(( "Scroll times %d\n", scroll_times - s ));
770 if ( scroll_times - s > DROWS - 3 ) {
772 dc_printf( " Press a key...B for back\n" );
786 dc_printf( "Typing '? function_name' will give the current status.\n" );
787 dc_printf( "Typing 'function_name ?' will give help on the function.\n" );
788 dc_printf( "Typing ? or help will give you help.\n");
789 dc_printf( "F3 selects last command line.\n" );