2 * $Logfile: /Freespace2/code/DebugConsole/Console.cpp $
7 * Routines for managing the debug console window.
10 * Revision 1.2 2002/05/07 03:16:43 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:08 root
17 * 4 6/04/99 10:35a Dave
19 * 3 10/13/98 9:28a Dave
20 * Started neatening up freespace.h. Many variables renamed and
21 * reorganized. Added AlphaColors.[h,cpp]
23 * 2 10/07/98 10:52a Dave
26 * 1 10/07/98 10:48a Dave
28 * 17 2/05/98 11:43a Allender
29 * enhcanced network statistic collection. Made callback in debug console
30 * to do networking if player is in the console
32 * 16 1/22/98 6:42p John
33 * Move game_flush out of debug console into freespace. Made object
34 * pair code throw out some weapons that turn. Added stats for how many
35 * object pair are actually checked.
37 * 15 1/16/98 11:56a Allender
38 * ability to scroll back in debug console, and call game_flush() when
41 * 14 1/10/98 1:14p John
42 * Added explanation to debug console commands
44 * 13 12/21/97 4:39p John
45 * fixed bug in name compare
47 * 12 12/21/97 4:33p John
48 * Made debug console functions a class that registers itself
49 * automatically, so you don't need to add the function to
52 * 11 9/13/97 9:31a Lawrance
53 * if playing a demo, clear key filter then reset it once done with debug
56 * 10 9/09/97 3:39p Sandeep
57 * warning level 4 bugs
59 * 9 6/13/97 3:50p John
60 * sped up debug console printf
62 * 8 6/13/97 3:27p John
63 * made debug console pretty
65 * 7 6/09/97 9:24a John
66 * Changed the way fonts are set.
68 * 6 5/29/97 3:09p John
69 * Took out debug menu.
70 * Made software scaler draw larger bitmaps.
71 * Optimized Direct3D some.
73 * 5 5/13/97 4:07p John
74 * made numbers also be marked as strings.
76 * 4 4/28/97 5:24p John
77 * made so : and \ don't get parsed out in debug console.
79 * 3 4/24/97 11:49a John
80 * added new lighting commands to console.
82 * 2 4/24/97 10:36a John
83 * moved the debug console stuff into it's own lib... made it compile with
86 * 1 4/24/97 10:16a John
99 #include "freespace.h"
104 #include "alphacolors.h"
107 #define MAX_COMMANDS 300
109 static int Num_debug_commands = 0;
110 static debug_command *Debug_command[MAX_COMMANDS];
113 debug_command::debug_command(char *_name, char *_help, void (*_func)() )
117 if ( Num_debug_commands >= MAX_COMMANDS ) {
118 Int3(); // Too many debug console commands!! Increase MAX_COMMANDS!!
122 for (i=0; i<Num_debug_commands; i++ ) {
123 int ret = stricmp( Debug_command[i]->name, _name );
126 Int3(); // This debug console command already exists!!!!
128 } else if ( ret > 0 ) {
129 break; // Insert it here
131 } else if ( ret < 0 ) {
136 if ( i < Num_debug_commands ) {
137 // Insert it at element i
139 for (j=Num_debug_commands; j>i; j-- ) {
140 Debug_command[j] = Debug_command[j-1];
142 Debug_command[i] = this;
143 Num_debug_commands++;
145 Debug_command[Num_debug_commands] = this;
146 Num_debug_commands++;
154 // some global variables
155 int Dc_command; // If this is set, then process the command
156 int Dc_help; // If this is set, then print out the help text in the form, "usage: ... \nLong description\n" );
157 int Dc_status; // If this is set, then print out the current status of the command.
158 char *Dc_arg; // The (lowercased) string value of the argument retrieved from dc_arg
159 char *Dc_arg_org; // Dc_arg before it got converted to lowercase
160 uint Dc_arg_type; // The type of dc_arg.
161 char *Dc_command_line; // The rest of the command line, from the end of the last processed arg on.
162 int Dc_arg_int; // If Dc_arg_type & ARG_INT is set, then this is the value
163 float Dc_arg_float; // If Dc_arg_type & ARG_FLOAT is set, then this is the value
165 int scroll_times = 0; // incremented each time display scrolls
167 int debug_inited = 0;
172 int debug_x=0, debug_y=0;
173 char debug_text[DROWS][DCOLS];
176 static char command_line[1024];
177 static int command_line_pos = 0;
178 #define DEBUG_HISTORY 16
179 static char oldcommand_line[DEBUG_HISTORY][1024];
180 int last_oldcommand=-1;
181 int command_scroll = 0;
183 ///=========================== SCANNER =======================
185 LETTER, QUOTE, SPECIAL, EOF_CODE, DIGIT,
189 NO_TOKEN, IDENTIFIER, NUMBER, STRING,
193 #define MAX_TOKEN_STRING_LENGTH 128
196 TOKEN_CODE scanner_token;
198 char scanner_token_string[MAX_TOKEN_STRING_LENGTH];
199 char scanner_word_string[MAX_TOKEN_STRING_LENGTH];
200 char * scanner_bufferp = "";
201 char * scanner_tokenp = scanner_token_string;
203 CHAR_CODE scanner_char_table[256];
205 #define scanner_char_code(x) scanner_char_table[x]
207 void scanner_get_char()
209 if ( *scanner_bufferp == '\0' ) {
213 scanner_ch = *scanner_bufferp++;
219 for (ch=0; ch<256; ++ch) scanner_char_table[ch] = SPECIAL;
220 for (ch='0'; ch<='9'; ++ch) scanner_char_table[ch] = DIGIT;
221 for (ch='A'; ch<='Z'; ++ch) scanner_char_table[ch] = LETTER;
222 for (ch='a'; ch<='z'; ++ch) scanner_char_table[ch] = LETTER;
224 scanner_char_table['.'] = DIGIT;
225 scanner_char_table['-'] = DIGIT;
226 scanner_char_table['+'] = DIGIT;
228 scanner_char_table['_'] = LETTER;
229 scanner_char_table[34] = QUOTE;
230 scanner_char_table[0] = EOF_CODE;
233 scanner_char_table[':'] = LETTER;
234 scanner_char_table['\\'] = LETTER;
240 void scanner_skip_blanks()
242 while( (scanner_ch ==' ') || (scanner_ch =='\t') )
247 void scanner_downshift_word()
249 int offset = 'a' - 'A';
252 strcpy( scanner_word_string, scanner_token_string );
254 tp = scanner_word_string;
256 *tp = (char)((*tp>='A') && (*tp <='Z') ? *tp + offset : *tp) ;
258 } while (*tp != '\0' );
262 void scanner_get_word()
264 while( (scanner_char_code(scanner_ch)==LETTER) || (scanner_char_code(scanner_ch)==DIGIT) ) {
265 *scanner_tokenp++ = scanner_ch;
268 *scanner_tokenp = '\0';
270 scanner_token = IDENTIFIER;
274 void scanner_get_string()
276 *scanner_tokenp++ = 34;
279 while(scanner_ch != 34 ) {
280 *scanner_tokenp++ = scanner_ch;
284 *scanner_tokenp++ = 34;
285 *scanner_tokenp = '\0';
286 scanner_token = STRING;
291 void scanner_get_token()
293 scanner_skip_blanks();
294 scanner_tokenp = scanner_token_string;
298 switch( scanner_char_code(scanner_ch) ) {
299 case QUOTE: scanner_get_string(); break;
300 case EOF_CODE: scanner_token = NO_TOKEN; break;
302 case LETTER: scanner_get_word(); break;
304 *scanner_tokenp++ = scanner_ch;
305 *scanner_tokenp = '\0';
307 scanner_token = IDENTIFIER;
311 scanner_downshift_word();
314 void scanner_start_command( char * s )
324 void dc_get_arg(uint type)
328 Dc_command_line = scanner_bufferp;
329 Dc_arg_org = scanner_token_string;
330 Dc_arg = scanner_word_string;
333 dc_printf( "next arg is '%s', was originally '%s'\n", Dc_arg, Dc_arg_org );
334 dc_printf( "Rest of the command line is '%s'\n", Dc_command_line );
337 if ( scanner_token == NO_TOKEN ) {
338 Dc_arg_type = ARG_NONE;
339 } else if ( scanner_token == IDENTIFIER ) {
340 Dc_arg_type = ARG_STRING;
341 } else if ( scanner_token == STRING ) {
342 Dc_arg_type = ARG_QUOTE;
344 Dc_arg_type = ARG_STRING;
347 if ( Dc_arg_type & ARG_STRING ) {
348 int i, num_digits, len;
350 len = strlen(Dc_arg);
353 for (i=0; i<len; i++)
354 if ( scanner_char_table[Dc_arg[i]] == DIGIT ) num_digits++;
356 if ( num_digits==len ) {
357 Dc_arg_type |= ARG_FLOAT;
358 Dc_arg_float = (float)atof(Dc_arg);
359 if ( !strchr( Dc_arg, '.' )) {
360 Dc_arg_type |= ARG_INT;
361 Dc_arg_int = atoi(Dc_arg);
364 if ( (Dc_arg[0] == '0') && (Dc_arg[1] == 'x') ) {
367 n = strtol(Dc_arg,&p,0);
369 Dc_arg_type |= ARG_INT|ARG_HEX;
376 if ( Dc_arg_type & ARG_FLOAT )
377 dc_printf( "Found float number! %f\n", Dc_arg_float );
379 if ( Dc_arg_type & ARG_INT )
380 dc_printf( "Found int number! %d\n", Dc_arg_int );
382 if ( Dc_arg_type & ARG_HEX )
383 dc_printf( "Found hex number! 0x%x\n", Dc_arg_int );
386 if ( !stricmp( Dc_arg, "on" ))
387 Dc_arg_type |= ARG_TRUE;
388 if ( !stricmp( Dc_arg, "true" ))
389 Dc_arg_type |= ARG_TRUE;
390 if ( !stricmp( Dc_arg, "off" ))
391 Dc_arg_type |= ARG_FALSE;
392 if ( !stricmp( Dc_arg, "false" ))
393 Dc_arg_type |= ARG_FALSE;
395 if ( !stricmp( Dc_arg, "+" ))
396 Dc_arg_type |= ARG_PLUS;
398 if ( !stricmp( Dc_arg, "-" ))
399 Dc_arg_type |= ARG_MINUS;
401 if ( !stricmp( Dc_arg, "," ))
402 Dc_arg_type |= ARG_COMMA;
405 if ( Dc_arg_type & ARG_INT) {
407 Dc_arg_type |= ARG_TRUE;
409 Dc_arg_type |= ARG_FALSE;
412 if ( !(Dc_arg_type&type) ) {
413 if ( (Dc_arg_type & ARG_NONE) && !(type & ARG_NONE))
414 dc_printf( "Error: Not enough parameters.\n" );
416 dc_printf( "Error: '%s' invalid type\n", Dc_arg );
417 longjmp(dc_bad_arg,1);
424 void debug_do_command(char * command)
430 if ( strlen(command) < 1 ) return;
433 Dc_command_line = command;
434 scanner_start_command(command);
436 if (setjmp(dc_bad_arg) ) {
440 dc_get_arg( ARG_ANY );
442 if ( !strcmp( Dc_arg, "debug" ) ) {
444 dc_printf( "Command line: '%s'\n", Dc_command_line );
445 dc_get_arg( ARG_ANY );
448 if ( !strcmp( Dc_arg, "?" ) ) {
450 dc_get_arg( ARG_ANY );
452 if ( Dc_arg_type&ARG_NONE ) {
458 if ( !strcmp( Dc_arg, "help" ) || !strcmp( Dc_arg, "man" ) ) {
460 dc_get_arg( ARG_ANY );
461 if ( Dc_arg_type&ARG_NONE ) {
467 if ( strstr( Dc_command_line, "?" ) ) {
471 if ( !(Dc_arg_type&ARG_STRING) ) {
472 dc_printf( "Invalid keyword '%s'\n", Dc_arg );
478 dc_printf( "Searching for command '%s'\n", Dc_arg );
481 for (i=0; i<Num_debug_commands; i++ ) {
482 if ( !stricmp( Debug_command[i]->name, Dc_arg )) {
486 dc_printf( "Calling function '%s'\n", Dc_arg );
490 } else if (mode==1) {
492 dc_printf( "Checking status for '%s'\n", Dc_arg );
498 dc_printf( "Doing help for '%s'\n", Dc_arg );
504 (*Debug_command[i]->func)();
508 if (!(Dc_arg_type&ARG_NONE)) {
509 dc_printf( "Ignoring the unused command line tail '%s %s'\n", Dc_arg_org, Dc_command_line );
517 dc_printf( "Unknown command '%s'\n", Dc_arg );
526 gr_set_color_fast( &Color_bright );
527 gr_string( 0x8000, 3, "Debug Console" );
529 gr_set_color_fast( &Color_normal );
531 for (i=0; i<DROWS; i++ ) {
532 gr_string( 0, i*16+16, debug_text[i] );
535 int t = timer_get_fixed_seconds() / (F1_0/3);
540 c = debug_text[debug_y][command_line_pos+1];
541 debug_text[debug_y][command_line_pos+1] = 0;
543 gr_get_string_size( &w, &h, debug_text[debug_y] );
545 //gr_string( w, debug_y*16, "_" );
546 gr_rect(w+1,debug_y*16+1+16,2,14);
548 debug_text[debug_y][command_line_pos+1] = c;
555 void debug_output( char c )
558 int next_tab = ((debug_x/28)+1)*28;
560 if ( next_tab >= DCOLS-1 ) {
564 if ( debug_y >= DROWS ) {
566 for (i=1; i<DROWS; i++ )
567 strcpy( debug_text[i-1], debug_text[i] );
570 debug_text[debug_y][debug_x] = 0;
572 debug_text[debug_y][debug_x] = 0;
576 for ( ; debug_x < next_tab; )
577 debug_text[debug_y][debug_x++] = ' ';
578 debug_text[debug_y][debug_x] = 0;
582 if ( (c == '\n') || (debug_x >= DCOLS-1) ) {
586 if ( debug_y >= DROWS ) {
588 for (i=1; i<DROWS; i++ )
589 strcpy( debug_text[i-1], debug_text[i] );
592 debug_text[debug_y][debug_x] = 0;
594 debug_text[debug_y][debug_x] = 0;
595 if ( c == '\n' ) return;
598 debug_text[debug_y][debug_x++] = c;
599 debug_text[debug_y][debug_x] = 0;
602 void dc_printf(char *format, ...)
607 va_start(args, format);
608 vsprintf(tmp, format, args);
623 if ( debug_inited ) return;
630 for (i=0; i<DROWS; i++ ) {
631 debug_text[i][0] = 0;
634 dc_printf("Debug console started.\n" );
638 void debug_console( void (*_func)() )
644 while( key_inkey() ){
648 if ( !debug_inited ) debug_init();
660 case KEY_SHIFTED+KEY_ENTER:
665 if ( command_line_pos > 0 ) {
666 command_line[--command_line_pos] = 0;
671 if ( last_oldcommand > -1 ) {
672 strcpy( command_line, oldcommand_line[last_oldcommand] );
673 command_line_pos = strlen(command_line);
674 command_line[command_line_pos] = 0;
680 if (command_scroll<0)
681 command_scroll = last_oldcommand;
683 if ( command_scroll > -1 ) {
684 strcpy( command_line, oldcommand_line[command_scroll] );
685 command_line_pos = strlen(command_line);
686 command_line[command_line_pos] = 0;
692 if (command_scroll>last_oldcommand)
694 if (command_scroll>last_oldcommand)
696 if ( command_scroll > -1 ) {
697 strcpy( command_line, oldcommand_line[command_scroll] );
698 command_line_pos = strlen(command_line);
699 command_line[command_line_pos] = 0;
704 debug_output( '\n' );
707 debug_do_command(command_line);
710 for (i=0; i<=last_oldcommand; i++ ) {
711 if (!stricmp( oldcommand_line[i], command_line )) {
716 if ( last_oldcommand < DEBUG_HISTORY-1 ) {
718 strcpy( oldcommand_line[last_oldcommand], command_line);
721 for (i=0; i<last_oldcommand; i++ ) {
722 strcpy( oldcommand_line[i], oldcommand_line[i+1] );
724 strcpy( oldcommand_line[last_oldcommand], command_line);
728 // for (i=0; i<=last_oldcommand; i++ ) {
729 // dc_printf( "OC %d. %s\n", i, oldcommand_line[i] );
732 debug_output( '\n' );
733 command_line_pos = 0;
734 command_line[command_line_pos] = 0;
741 ubyte c = (ubyte)key_to_ascii(k);
743 command_line[command_line_pos++] = c;
744 command_line[command_line_pos] = 0;
749 strcpy( debug_text[debug_y], ">" );
750 strcat( debug_text[debug_y], command_line );
758 while( key_inkey() ){
767 dc_printf( "Available functions:\n\n" );
770 for (i=0; i<Num_debug_commands; i++ ) {
771 dc_printf( " %s - %s\n", Debug_command[i]->name, Debug_command[i]->help );
772 //mprintf(( "Scroll times %d\n", scroll_times - s ));
773 if ( scroll_times - s > DROWS - 3 ) {
775 dc_printf( " Press a key...B for back\n" );
789 dc_printf( "Typing '? function_name' will give the current status.\n" );
790 dc_printf( "Typing 'function_name ?' will give help on the function.\n" );
791 dc_printf( "Typing ? or help will give you help.\n");
792 dc_printf( "F3 selects last command line.\n" );