/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ /* * $Logfile: /Freespace2/code/DebugConsole/Console.cpp $ * $Revision: 2.6 $ * $Date: 2005-04-25 00:07:22 $ * $Author: wmcoolmon $ * * Routines for managing the debug console window. * * $Log: not supported by cvs2svn $ * Revision 2.5 2004/07/26 20:47:27 Kazan * remove MCD complete * * Revision 2.4 2004/07/12 16:32:44 Kazan * MCD - define _MCD_CHECK to use memory tracking * * Revision 2.3 2004/03/05 09:01:58 Goober5000 * Uber pass at reducing #includes * --Goober5000 * * Revision 2.2 2003/03/18 10:07:01 unknownplayer * The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can. * * Revision 2.1.2.1 2002/09/24 18:56:41 randomtiger * DX8 branch commit * * This is the scub of UP's previous code with the more up to date RT code. * For full details check previous dev e-mails * * Revision 2.1 2002/08/01 01:41:04 penguin * The big include file move * * Revision 2.0 2002/06/03 04:02:21 penguin * Warpcore CVS sync * * Revision 1.1 2002/05/02 18:03:04 mharris * Initial checkin - converted filenames and includes to lower case * * * 4 6/04/99 10:35a Dave * * 3 10/13/98 9:28a Dave * Started neatening up freespace.h. Many variables renamed and * reorganized. Added AlphaColors.[h,cpp] * * 2 10/07/98 10:52a Dave * Initial checkin. * * 1 10/07/98 10:48a Dave * * 17 2/05/98 11:43a Allender * enhcanced network statistic collection. Made callback in debug console * to do networking if player is in the console * * 16 1/22/98 6:42p John * Move game_flush out of debug console into freespace. Made object * pair code throw out some weapons that turn. Added stats for how many * object pair are actually checked. * * 15 1/16/98 11:56a Allender * ability to scroll back in debug console, and call game_flush() when * leaving * * 14 1/10/98 1:14p John * Added explanation to debug console commands * * 13 12/21/97 4:39p John * fixed bug in name compare * * 12 12/21/97 4:33p John * Made debug console functions a class that registers itself * automatically, so you don't need to add the function to * debugfunctions.cpp. * * 11 9/13/97 9:31a Lawrance * if playing a demo, clear key filter then reset it once done with debug * console * * 10 9/09/97 3:39p Sandeep * warning level 4 bugs * * 9 6/13/97 3:50p John * sped up debug console printf * * 8 6/13/97 3:27p John * made debug console pretty * * 7 6/09/97 9:24a John * Changed the way fonts are set. * * 6 5/29/97 3:09p John * Took out debug menu. * Made software scaler draw larger bitmaps. * Optimized Direct3D some. * * 5 5/13/97 4:07p John * made numbers also be marked as strings. * * 4 4/28/97 5:24p John * made so : and \ don't get parsed out in debug console. * * 3 4/24/97 11:49a John * added new lighting commands to console. * * 2 4/24/97 10:36a John * moved the debug console stuff into it's own lib... made it compile with * Fred. * * 1 4/24/97 10:16a John * Initial rev * * $NoKeywords: $ */ #include #include #include #include #include #include "globalincs/pstypes.h" #include "graphics/font.h" #include "io/timer.h" #include "io/key.h" #include "globalincs/alphacolors.h" #include "osapi/osapi.h" #include "debugconsole/dbugfile.h" #define MAX_COMMANDS 300 static int Num_debug_commands = 0; static debug_command *Debug_command[MAX_COMMANDS]; debug_command::debug_command(char *_name, char *_help, void (*_func)() ) { int i; if ( Num_debug_commands >= MAX_COMMANDS ) { Int3(); // Too many debug console commands!! Increase MAX_COMMANDS!! return; } for (i=0; iname, _name ); if ( ret == 0) { Int3(); // This debug console command already exists!!!! return; } else if ( ret > 0 ) { break; // Insert it here } else if ( ret < 0 ) { // do nothing } } if ( i < Num_debug_commands ) { // Insert it at element i int j; for (j=Num_debug_commands; j>i; j-- ) { Debug_command[j] = Debug_command[j-1]; } Debug_command[i] = this; Num_debug_commands++; } else { Debug_command[Num_debug_commands] = this; Num_debug_commands++; } name = _name; help = _help; func = _func; } // some global variables int Dc_command; // If this is set, then process the command int Dc_help; // If this is set, then print out the help text in the form, "usage: ... \nLong description\n" ); int Dc_status; // If this is set, then print out the current status of the command. char *Dc_arg; // The (lowercased) string value of the argument retrieved from dc_arg char *Dc_arg_org; // Dc_arg before it got converted to lowercase uint Dc_arg_type; // The type of dc_arg. char *Dc_command_line; // The rest of the command line, from the end of the last processed arg on. int Dc_arg_int; // If Dc_arg_type & ARG_INT is set, then this is the value float Dc_arg_float; // If Dc_arg_type & ARG_FLOAT is set, then this is the value int scroll_times = 0; // incremented each time display scrolls int debug_inited = 0; #define DROWS 25 #define DCOLS 80 int debug_x=0, debug_y=0; char debug_text[DROWS][DCOLS]; static char command_line[1024]; static int command_line_pos = 0; #define DEBUG_HISTORY 16 static char oldcommand_line[DEBUG_HISTORY][1024]; int last_oldcommand=-1; int command_scroll = 0; ///=========================== SCANNER ======================= typedef enum { LETTER, QUOTE, SPECIAL, EOF_CODE, DIGIT, } CHAR_CODE; typedef enum { NO_TOKEN, IDENTIFIER, NUMBER, STRING, } TOKEN_CODE; #define MAX_TOKEN_STRING_LENGTH 128 char scanner_ch; TOKEN_CODE scanner_token; char scanner_token_string[MAX_TOKEN_STRING_LENGTH]; char scanner_word_string[MAX_TOKEN_STRING_LENGTH]; char * scanner_bufferp = ""; char * scanner_tokenp = scanner_token_string; CHAR_CODE scanner_char_table[256]; #define scanner_char_code(x) scanner_char_table[x] void scanner_get_char() { if ( *scanner_bufferp == '\0' ) { scanner_ch = 0; return; } scanner_ch = *scanner_bufferp++; } void scanner_init() { int ch; for (ch=0; ch<256; ++ch) scanner_char_table[ch] = SPECIAL; for (ch='0'; ch<='9'; ++ch) scanner_char_table[ch] = DIGIT; for (ch='A'; ch<='Z'; ++ch) scanner_char_table[ch] = LETTER; for (ch='a'; ch<='z'; ++ch) scanner_char_table[ch] = LETTER; scanner_char_table['.'] = DIGIT; scanner_char_table['-'] = DIGIT; scanner_char_table['+'] = DIGIT; scanner_char_table['_'] = LETTER; scanner_char_table[34] = QUOTE; scanner_char_table[0] = EOF_CODE; scanner_char_table[':'] = LETTER; scanner_char_table['\\'] = LETTER; scanner_ch = 0; } void scanner_skip_blanks() { while( (scanner_ch ==' ') || (scanner_ch =='\t') ) scanner_get_char(); } void scanner_downshift_word() { int offset = 'a' - 'A'; char * tp; strcpy( scanner_word_string, scanner_token_string ); tp = scanner_word_string; do { *tp = (char)((*tp>='A') && (*tp <='Z') ? *tp + offset : *tp) ; tp++; } while (*tp != '\0' ); } void scanner_get_word() { while( (scanner_char_code(scanner_ch)==LETTER) || (scanner_char_code(scanner_ch)==DIGIT) ) { *scanner_tokenp++ = scanner_ch; scanner_get_char(); } *scanner_tokenp = '\0'; scanner_token = IDENTIFIER; } void scanner_get_string() { *scanner_tokenp++ = 34; scanner_get_char(); while(scanner_ch != 34 ) { *scanner_tokenp++ = scanner_ch; scanner_get_char(); } scanner_get_char(); *scanner_tokenp++ = 34; *scanner_tokenp = '\0'; scanner_token = STRING; } void scanner_get_token() { scanner_skip_blanks(); scanner_tokenp = scanner_token_string; *scanner_tokenp = 0; switch( scanner_char_code(scanner_ch) ) { case QUOTE: scanner_get_string(); break; case EOF_CODE: scanner_token = NO_TOKEN; break; case DIGIT: case LETTER: scanner_get_word(); break; default: *scanner_tokenp++ = scanner_ch; *scanner_tokenp = '\0'; scanner_get_char(); scanner_token = IDENTIFIER; break; } scanner_downshift_word(); } void scanner_start_command( char * s ) { scanner_bufferp = s; scanner_get_char(); } int Dc_debug_on = 0; jmp_buf dc_bad_arg; void dc_get_arg(uint type) { scanner_get_token(); Dc_command_line = scanner_bufferp; Dc_arg_org = scanner_token_string; Dc_arg = scanner_word_string; if (Dc_debug_on) { dc_printf( "next arg is '%s', was originally '%s'\n", Dc_arg, Dc_arg_org ); dc_printf( "Rest of the command line is '%s'\n", Dc_command_line ); } if ( scanner_token == NO_TOKEN ) { Dc_arg_type = ARG_NONE; } else if ( scanner_token == IDENTIFIER ) { Dc_arg_type = ARG_STRING; } else if ( scanner_token == STRING ) { Dc_arg_type = ARG_QUOTE; } else { Dc_arg_type = ARG_STRING; } if ( Dc_arg_type & ARG_STRING ) { int i, num_digits, len; len = strlen(Dc_arg); num_digits = 0; for (i=0; iname, Dc_arg )) { if (mode==0) { if (Dc_debug_on) dc_printf( "Calling function '%s'\n", Dc_arg ); Dc_command = 1; Dc_help = 0; Dc_status = 1; } else if (mode==1) { if (Dc_debug_on) dc_printf( "Checking status for '%s'\n", Dc_arg ); Dc_command = 0; Dc_help = 0; Dc_status = 1; } else { if (Dc_debug_on) dc_printf( "Doing help for '%s'\n", Dc_arg ); Dc_command = 0; Dc_help = 1; Dc_status = 0; } (*Debug_command[i]->func)(); if (mode==0) { dc_get_arg(ARG_ANY); if (!(Dc_arg_type&ARG_NONE)) { dc_printf( "Ignoring the unused command line tail '%s %s'\n", Dc_arg_org, Dc_command_line ); } } return; } } dc_printf( "Unknown command '%s'\n", Dc_arg ); } void debug_draw() { int i; gr_clear(); gr_set_font(FONT1); gr_set_color_fast( &Color_bright ); gr_string( 0x8000, 3, "Debug Console" ); gr_set_color_fast( &Color_normal ); for (i=0; i= DCOLS-1 ) { debug_x=0; debug_y++; scroll_times++; if ( debug_y >= DROWS ) { int i; for (i=1; i= DCOLS-1) ) { debug_x=0; debug_y++; scroll_times++; if ( debug_y >= DROWS ) { int i; for (i=1; i 0 ) { command_line[--command_line_pos] = 0; } break; case KEY_F3: if ( last_oldcommand > -1 ) { strcpy( command_line, oldcommand_line[last_oldcommand] ); command_line_pos = strlen(command_line); command_line[command_line_pos] = 0; } break; case KEY_UP: command_scroll--; if (command_scroll<0) command_scroll = last_oldcommand; if ( command_scroll > -1 ) { strcpy( command_line, oldcommand_line[command_scroll] ); command_line_pos = strlen(command_line); command_line[command_line_pos] = 0; } break; case KEY_DOWN: command_scroll++; if (command_scroll>last_oldcommand) command_scroll = 0; if (command_scroll>last_oldcommand) command_scroll = -1; if ( command_scroll > -1 ) { strcpy( command_line, oldcommand_line[command_scroll] ); command_line_pos = strlen(command_line); command_line[command_line_pos] = 0; } break; case KEY_ENTER: { debug_output( '\n' ); debug_draw(); debug_do_command(command_line); int i, found = 0; for (i=0; i<=last_oldcommand; i++ ) { if (!stricmp( oldcommand_line[i], command_line )) { found = 1; } } if ( !found ) { if ( last_oldcommand < DEBUG_HISTORY-1 ) { last_oldcommand++; strcpy( oldcommand_line[last_oldcommand], command_line); } else { int i; for (i=0; i" ); strcat( debug_text[debug_y], command_line ); debug_draw(); if ( _func ){ _func(); } } while( key_inkey() ){ os_poll(); } } void debug_help() { int s, i; dc_printf( "Available functions:\n\n" ); s = scroll_times; for (i=0; iname, Debug_command[i]->help ); //mprintf(( "Scroll times %d\n", scroll_times - s )); if ( scroll_times - s > DROWS - 3 ) { int k; dc_printf( " Press a key...B for back\n" ); debug_draw(); k = key_getch(); s = scroll_times; if ( k == KEY_B ) { i -= ((DROWS-3)*2); if ( i <= 0 ) i = -1; } } debug_draw(); } dc_printf( "\n" ); dc_printf( "Typing '? function_name' will give the current status.\n" ); dc_printf( "Typing 'function_name ?' will give help on the function.\n" ); dc_printf( "Typing ? or help will give you help.\n"); dc_printf( "F3 selects last command line.\n" ); }