]> icculus.org git repositories - taylor/freespace2.git/blob - src/debugconsole/console.cpp
fix control binding
[taylor/freespace2.git] / src / debugconsole / console.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/DebugConsole/Console.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Routines for managing the debug console window.
16  *
17  * $Log$
18  * Revision 1.4  2004/07/04 11:31:43  taylor
19  * amd64 support, compiler warning fixes, don't use software rendering
20  *
21  * Revision 1.3  2002/06/09 04:41:16  relnev
22  * added copyright header
23  *
24  * Revision 1.2  2002/05/07 03:16:43  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:08  root
28  * Initial import.
29  *
30  * 
31  * 4     6/04/99 10:35a Dave
32  * 
33  * 3     10/13/98 9:28a Dave
34  * Started neatening up freespace.h. Many variables renamed and
35  * reorganized. Added AlphaColors.[h,cpp]
36  * 
37  * 2     10/07/98 10:52a Dave
38  * Initial checkin.
39  * 
40  * 1     10/07/98 10:48a Dave
41  * 
42  * 17    2/05/98 11:43a Allender
43  * enhcanced network statistic collection.  Made callback in debug console
44  * to do networking if player is in the console
45  * 
46  * 16    1/22/98 6:42p John
47  * Move game_flush out of debug console into freespace.     Made object
48  * pair code throw out some weapons that turn.   Added stats for how many
49  * object pair are actually checked.
50  * 
51  * 15    1/16/98 11:56a Allender
52  * ability to scroll back in debug console, and call game_flush() when
53  * leaving
54  * 
55  * 14    1/10/98 1:14p John
56  * Added explanation to debug console commands
57  * 
58  * 13    12/21/97 4:39p John
59  * fixed bug in name compare
60  * 
61  * 12    12/21/97 4:33p John
62  * Made debug console functions a class that registers itself
63  * automatically, so you don't need to add the function to
64  * debugfunctions.cpp.  
65  * 
66  * 11    9/13/97 9:31a Lawrance
67  * if playing a demo, clear key filter then reset it once done with debug
68  * console
69  * 
70  * 10    9/09/97 3:39p Sandeep
71  * warning level 4 bugs
72  * 
73  * 9     6/13/97 3:50p John
74  * sped up debug console printf
75  * 
76  * 8     6/13/97 3:27p John
77  * made debug console pretty
78  * 
79  * 7     6/09/97 9:24a John
80  * Changed the way fonts are set.
81  * 
82  * 6     5/29/97 3:09p John
83  * Took out debug menu.  
84  * Made software scaler draw larger bitmaps.
85  * Optimized Direct3D some.
86  * 
87  * 5     5/13/97 4:07p John
88  * made numbers also be marked as strings.
89  * 
90  * 4     4/28/97 5:24p John
91  * made so : and \ don't get parsed out in debug console.
92  * 
93  * 3     4/24/97 11:49a John
94  * added new lighting commands to console.
95  * 
96  * 2     4/24/97 10:36a John
97  * moved the debug console stuff into it's own lib... made it compile with
98  * Fred.
99  * 
100  * 1     4/24/97 10:16a John
101  * Initial rev
102  *
103  * $NoKeywords: $
104  */
105
106 #include <stdlib.h>
107 #include <stdio.h>
108 #include <stdarg.h>
109 #include <string.h>
110
111 #include "pstypes.h"
112 #include "freespace.h"
113 #include "font.h"
114 #include "timer.h"
115 #include "2d.h"
116 #include "key.h"
117 #include "alphacolors.h"
118 #include "osapi.h"
119
120 #define MAX_COMMANDS 300
121
122 static int Num_debug_commands = 0;
123 static debug_command *Debug_command[MAX_COMMANDS];
124
125
126 debug_command::debug_command(const char *_name, const char *_help, void (*_func)() )
127 {
128         int i;
129
130         if ( Num_debug_commands >= MAX_COMMANDS )       {
131                 Int3();                 // Too many debug console commands!! Increase MAX_COMMANDS!!
132                 return;
133         }
134
135         for (i=0; i<Num_debug_commands; i++ )   {
136                 int ret  = SDL_strcasecmp( Debug_command[i]->name, _name );
137
138                 if ( ret == 0)  {
139                         Int3();         // This debug console command already exists!!!! 
140                         return;
141                 } else if ( ret > 0 )   {
142                         break;          // Insert it here
143
144                 } else if ( ret < 0 )   {
145                         // do nothing
146                 }
147         }
148
149         if ( i < Num_debug_commands )   {
150                 // Insert it at element i
151                 int j;
152                 for (j=Num_debug_commands; j>i; j-- )   {
153                         Debug_command[j] = Debug_command[j-1];
154                 }
155                 Debug_command[i] = this;                
156                 Num_debug_commands++;
157         } else {
158                 Debug_command[Num_debug_commands] = this;               
159                 Num_debug_commands++;
160         }
161
162         name = _name;
163         help = _help;
164         func = _func;
165 }
166
167 // some global variables
168 int Dc_command; // If this is set, then process the command
169 int Dc_help;            // If this is set, then print out the help text in the form, "usage: ... \nLong description\n" );
170 int Dc_status;          // If this is set, then print out the current status of the command.
171 char *Dc_arg;           // The (lowercased) string value of the argument retrieved from dc_arg
172 char *Dc_arg_org;       // Dc_arg before it got converted to lowercase
173 uint Dc_arg_type;       // The type of dc_arg.
174 const char *Dc_command_line;            // The rest of the command line, from the end of the last processed arg on.
175 int Dc_arg_int;         // If Dc_arg_type & ARG_INT is set, then this is the value
176 float Dc_arg_float;     // If Dc_arg_type & ARG_FLOAT is set, then this is the value
177
178 int scroll_times = 0;           // incremented each time display scrolls
179
180 int debug_inited = 0;
181
182 #define DROWS 25
183 #define DCOLS 80
184
185 int debug_x=0, debug_y=0;
186 char debug_text[DROWS][DCOLS];
187
188
189 static char command_line[1024];
190 static int command_line_pos = 0;
191 #define DEBUG_HISTORY 16
192 static char oldcommand_line[DEBUG_HISTORY][1024];
193 int last_oldcommand=-1;
194 int command_scroll = 0;
195
196 ///=========================== SCANNER =======================
197 typedef enum {
198         LETTER, QUOTE, SPECIAL, EOF_CODE, DIGIT,
199 } CHAR_CODE;
200
201 typedef enum {
202         NO_TOKEN, IDENTIFIER, NUMBER, STRING, 
203 } TOKEN_CODE;
204
205
206 #define MAX_TOKEN_STRING_LENGTH 128
207
208 char                    scanner_ch;
209 TOKEN_CODE      scanner_token;
210
211 char scanner_token_string[MAX_TOKEN_STRING_LENGTH];
212 char scanner_word_string[MAX_TOKEN_STRING_LENGTH];
213 const char * scanner_bufferp = "";
214 char * scanner_tokenp = scanner_token_string;
215
216 CHAR_CODE scanner_char_table[256];
217
218 #define scanner_char_code(x) scanner_char_table[x]
219
220 void scanner_get_char()
221 {
222         if ( *scanner_bufferp == '\0' ) {
223                 scanner_ch = 0;
224                 return;
225         }
226         scanner_ch = *scanner_bufferp++;
227 }
228
229 void scanner_init()
230 {
231         int ch;
232         for (ch=0; ch<256; ++ch) scanner_char_table[ch] = SPECIAL;
233         for (ch='0'; ch<='9'; ++ch) scanner_char_table[ch] = DIGIT;
234         for (ch='A'; ch<='Z'; ++ch) scanner_char_table[ch] = LETTER;
235         for (ch='a'; ch<='z'; ++ch) scanner_char_table[ch] = LETTER;
236
237         scanner_char_table[(int)'.'] = DIGIT;
238         scanner_char_table[(int)'-'] = DIGIT;
239         scanner_char_table[(int)'+'] = DIGIT;
240         
241         scanner_char_table[(int)'_'] = LETTER;
242         scanner_char_table[34] = QUOTE;
243         scanner_char_table[0] = EOF_CODE;
244
245
246         scanner_char_table[(int)':'] = LETTER;
247         scanner_char_table[(int)'\\'] = LETTER;
248
249         scanner_ch = 0;
250 }
251
252
253 void scanner_skip_blanks()
254 {
255         while( (scanner_ch ==' ') || (scanner_ch =='\t') ) 
256                 scanner_get_char();
257 }
258
259
260 void scanner_downshift_word()
261 {
262         int offset = 'a' - 'A';
263         char * tp;
264
265         SDL_strlcpy( scanner_word_string, scanner_token_string, SDL_arraysize(scanner_word_string) );
266         
267         tp = scanner_word_string;
268         do {
269                 *tp = (char)((*tp>='A') && (*tp <='Z') ? *tp + offset : *tp) ;
270                 tp++;
271         } while (*tp != '\0' );
272 }
273
274
275 void scanner_get_word()
276 {
277         while( (scanner_char_code((int)scanner_ch)==LETTER) || (scanner_char_code((int)scanner_ch)==DIGIT)  )   {
278                 *scanner_tokenp++ = scanner_ch;
279                 scanner_get_char();
280         }
281         *scanner_tokenp = '\0';
282
283         scanner_token = IDENTIFIER;
284 }
285
286
287 void scanner_get_string()
288 {
289         *scanner_tokenp++ = 34;
290         scanner_get_char();
291
292         while(scanner_ch != 34 )        {
293                 *scanner_tokenp++ = scanner_ch;
294                 scanner_get_char();
295         }
296         scanner_get_char();
297         *scanner_tokenp++ = 34;
298         *scanner_tokenp = '\0';
299         scanner_token = STRING;
300 }
301
302
303
304 void scanner_get_token()
305 {
306         scanner_skip_blanks();
307         scanner_tokenp = scanner_token_string;
308         *scanner_tokenp = 0;
309
310
311         switch( scanner_char_code((int)scanner_ch) )    {
312         case QUOTE:             scanner_get_string();   break;
313         case EOF_CODE:  scanner_token = NO_TOKEN;       break;
314         case DIGIT:
315         case LETTER:    scanner_get_word(); break;
316         default:                        
317                 *scanner_tokenp++ = scanner_ch;
318                 *scanner_tokenp = '\0';
319                 scanner_get_char();
320                 scanner_token = IDENTIFIER;
321                 break;
322         }
323
324         scanner_downshift_word();
325 }
326
327 void scanner_start_command( const char * s )
328 {
329         scanner_bufferp = s;
330         scanner_get_char();
331 }
332
333
334 int Dc_debug_on = 0;
335
336 void dc_get_arg(uint type)
337 {
338         scanner_get_token();
339
340         Dc_command_line = scanner_bufferp;      
341         Dc_arg_org = scanner_token_string;
342         Dc_arg = scanner_word_string;
343
344         if (Dc_debug_on)        {
345                 dc_printf( "next arg is '%s', was originally '%s'\n", Dc_arg, Dc_arg_org );
346                 dc_printf( "Rest of the command line is '%s'\n", Dc_command_line );
347         }
348         
349         if ( scanner_token == NO_TOKEN )        {
350                 Dc_arg_type = ARG_NONE;
351         } else if ( scanner_token == IDENTIFIER )       {
352                 Dc_arg_type = ARG_STRING;
353         } else if ( scanner_token == STRING )   {
354                 Dc_arg_type = ARG_QUOTE;
355         } else {
356                 Dc_arg_type = ARG_STRING;
357         }
358
359         if ( Dc_arg_type & ARG_STRING ) {
360                 int i, num_digits, len;
361
362                 len = strlen(Dc_arg);
363                 num_digits = 0;
364
365                 for (i=0; i<len; i++)
366                         if ( scanner_char_table[(int)Dc_arg[i]] == DIGIT ) num_digits++;
367
368                 if ( num_digits==len )  {
369                         Dc_arg_type |= ARG_FLOAT;
370                         Dc_arg_float = (float)atof(Dc_arg);
371                         if ( !SDL_strchr( Dc_arg, '.' ))        {
372                                 Dc_arg_type |= ARG_INT;
373                                 Dc_arg_int = atoi(Dc_arg);
374                         }
375                 } else {
376                         if ( (Dc_arg[0] == '0') && (Dc_arg[1] == 'x') ) {
377                                 char *p;
378                                 int n;
379                                 n = strtol(Dc_arg,&p,0);
380                                 if ( *p == 0 )  {
381                                         Dc_arg_type |= ARG_INT|ARG_HEX;
382                                         Dc_arg_int = n;
383                                 }
384                         } 
385                 }
386
387                 if (Dc_debug_on)        {
388                         if ( Dc_arg_type & ARG_FLOAT )
389                                 dc_printf( "Found float number! %f\n", Dc_arg_float );
390
391                         if ( Dc_arg_type & ARG_INT )
392                                 dc_printf( "Found int number! %d\n", Dc_arg_int );
393
394                         if ( Dc_arg_type & ARG_HEX )
395                                 dc_printf( "Found hex number! 0x%x\n", Dc_arg_int );
396                 }
397
398                 if ( !SDL_strcasecmp( Dc_arg, "on" ))
399                         Dc_arg_type |= ARG_TRUE;
400                 if ( !SDL_strcasecmp( Dc_arg, "true" ))
401                         Dc_arg_type |= ARG_TRUE;
402                 if ( !SDL_strcasecmp( Dc_arg, "off" ))
403                         Dc_arg_type |= ARG_FALSE;
404                 if ( !SDL_strcasecmp( Dc_arg, "false" ))
405                         Dc_arg_type |= ARG_FALSE;
406
407                 if ( !SDL_strcasecmp( Dc_arg, "+" ))
408                         Dc_arg_type |= ARG_PLUS;
409
410                 if ( !SDL_strcasecmp( Dc_arg, "-" ))
411                         Dc_arg_type |= ARG_MINUS;
412
413                 if ( !SDL_strcasecmp( Dc_arg, "," ))
414                         Dc_arg_type |= ARG_COMMA;
415         }
416
417         if ( Dc_arg_type & ARG_INT)     {
418                 if ( Dc_arg_int )       
419                         Dc_arg_type |= ARG_TRUE;
420                 else
421                         Dc_arg_type |= ARG_FALSE;
422         }
423
424         if ( !(Dc_arg_type&type) )      {
425                 if ( (Dc_arg_type & ARG_NONE) && !(type & ARG_NONE))    
426                         dc_printf( "Error: Not enough parameters.\n" );
427                 else
428                         dc_printf( "Error: '%s' invalid type\n", Dc_arg );
429
430                 throw (int)1;
431         }
432
433 }
434
435 void debug_help();
436
437 void debug_do_command(const char * command)
438 {
439
440         int i;
441         int mode = 0;
442
443         if ( strlen(command) < 1 ) return;
444         
445         Dc_debug_on = 0;
446         Dc_command_line = command;
447         scanner_start_command(command);
448
449         try {
450                 dc_get_arg( ARG_ANY );
451
452                 if ( !strcmp( Dc_arg, "debug" ) )       {
453                         Dc_debug_on = 1;
454                         dc_printf( "Command line: '%s'\n", Dc_command_line );
455                         dc_get_arg( ARG_ANY );
456                 }
457
458                 if ( !strcmp( Dc_arg, "?" ) )   {
459                         mode = 1;
460                         dc_get_arg( ARG_ANY );
461
462                         if ( Dc_arg_type&ARG_NONE )     {
463                                 debug_help();
464                                 return;
465                         }
466                 }
467
468                 if ( !strcmp( Dc_arg, "help" ) || !strcmp( Dc_arg, "man" ) )    {
469                         mode = 2;
470                         dc_get_arg( ARG_ANY );
471                         if ( Dc_arg_type&ARG_NONE )     {
472                                 debug_help();
473                                 return;
474                         }
475                 }
476
477                 if ( strstr( Dc_command_line, "?" ) )   {
478                         mode = 2;
479                 }
480
481                 if ( !(Dc_arg_type&ARG_STRING) )        {
482                         dc_printf( "Invalid keyword '%s'\n", Dc_arg );
483                         return;
484                 }
485
486
487                 if (Dc_debug_on)        {
488                         dc_printf( "Searching for command '%s'\n", Dc_arg );
489                 }
490
491                 for (i=0; i<Num_debug_commands; i++ )   {
492                         if ( !SDL_strcasecmp( Debug_command[i]->name, Dc_arg )) {
493
494                                 if (mode==0)    {
495                                         if (Dc_debug_on)
496                                                 dc_printf( "Calling function '%s'\n", Dc_arg );
497                                         Dc_command = 1;
498                                         Dc_help = 0;
499                                         Dc_status = 1;
500                                 } else if (mode==1) {
501                                         if (Dc_debug_on)
502                                                 dc_printf( "Checking status for '%s'\n", Dc_arg );
503                                         Dc_command = 0;
504                                         Dc_help = 0;
505                                         Dc_status = 1;
506                                 } else {
507                                         if (Dc_debug_on)
508                                                 dc_printf( "Doing help for '%s'\n", Dc_arg );
509                                         Dc_command = 0;
510                                         Dc_help = 1;
511                                         Dc_status = 0;
512                                 }
513
514                                 (*Debug_command[i]->func)();
515
516                                 if (mode==0)    {
517                                         dc_get_arg(ARG_ANY);
518                                         if (!(Dc_arg_type&ARG_NONE))    {
519                                                 dc_printf( "Ignoring the unused command line tail '%s %s'\n", Dc_arg_org, Dc_command_line );
520                                         }
521                                 }
522
523                                 return;
524                         }
525                 }
526         } catch (int) {
527                 return;
528         }
529
530         dc_printf( "Unknown command '%s'\n", Dc_arg );
531 }
532
533 void debug_draw()
534 {
535         int i;
536         
537         gr_clear();
538         gr_set_font(FONT1);
539         gr_set_color_fast( &Color_bright );
540         gr_string( 0x8000, 3, "Debug Console" );
541
542         gr_set_color_fast( &Color_normal );
543
544         for (i=0; i<DROWS; i++ )        {
545                 gr_string( 0, i*16+16, debug_text[i] );
546         }
547
548         int t = timer_get_fixed_seconds() / (F1_0/3);
549         if ( t & 1 )    {
550                 int w,h;
551                 char c;
552
553                 c = debug_text[debug_y][command_line_pos+1];
554                 debug_text[debug_y][command_line_pos+1] = 0;
555
556                 gr_get_string_size( &w, &h, debug_text[debug_y] );
557                 
558                 //gr_string( w, debug_y*16, "_" );
559                 gr_rect(w+1,debug_y*16+1+16,2,14);
560         
561                 debug_text[debug_y][command_line_pos+1] = c;
562         }
563
564         gr_flip();
565 }
566
567
568 void debug_output( char c )
569 {
570         if ( c == '\t' )        {
571                 int next_tab = ((debug_x/28)+1)*28;
572
573                 if ( next_tab >= DCOLS-1 )      {
574                         debug_x=0;
575                         debug_y++;
576                         scroll_times++;
577                         if ( debug_y >= DROWS ) {
578                                 int i;
579                                 for (i=1; i<DROWS; i++ )
580                                         SDL_strlcpy( debug_text[i-1], debug_text[i], DCOLS );
581                                 debug_y = DROWS-1;
582                                 debug_x = 0;
583                                 debug_text[debug_y][debug_x] = 0;
584                         }
585                         debug_text[debug_y][debug_x] = 0;
586                         return;
587                 }
588         
589                 for ( ; debug_x < next_tab; )
590                         debug_text[debug_y][debug_x++] = ' ';
591                 debug_text[debug_y][debug_x] = 0;
592                 return;
593         }
594
595         if ( (c == '\n') || (debug_x >= DCOLS-1) )      {
596                 debug_x=0;
597                 debug_y++;
598                 scroll_times++;
599                 if ( debug_y >= DROWS ) {
600                         int i;
601                         for (i=1; i<DROWS; i++ )
602                                 SDL_strlcpy( debug_text[i-1], debug_text[i], DCOLS );
603                         debug_y = DROWS-1;
604                         debug_x = 0;
605                         debug_text[debug_y][debug_x] = 0;
606                 }
607                 debug_text[debug_y][debug_x] = 0;
608                 if ( c == '\n' ) return;
609         }
610
611         debug_text[debug_y][debug_x++] = c;
612         debug_text[debug_y][debug_x] = 0;
613 }
614
615 void dc_printf(const char *format, ...)
616 {
617         char tmp[DCOLS*2];
618         va_list args;
619         
620         va_start(args, format);
621         SDL_vsnprintf(tmp, SDL_arraysize(tmp), format, args);
622         va_end(args);
623
624         char *p = tmp;
625         while( *p )     {
626                 debug_output(*p);
627                 p++;
628         } 
629 }
630
631
632
633 void debug_init()
634 {
635         int i;
636         if ( debug_inited ) return;
637
638         debug_inited = 1;
639
640         debug_x=0;
641         debug_y=0;
642
643         for (i=0; i<DROWS; i++ )        {
644                 debug_text[i][0] = 0;
645         }
646         
647         dc_printf("Debug console started.\n" );
648 }
649
650
651 void debug_console( void (*_func)() )
652 {
653         int done = 0;
654
655         scanner_init();
656
657         while( key_inkey() ){
658                 os_poll();
659         }
660
661         if ( !debug_inited ) debug_init();
662
663
664         debug_draw();
665         
666         while (!done)   {
667                 // poll the os
668                 os_poll();
669
670                 int k = key_inkey();
671                 switch( k )     {
672
673                 case KEY_SHIFTED+SDLK_RETURN:
674                 case SDLK_ESCAPE:
675                         done=1; break;
676
677                 case SDLK_BACKSPACE:
678                         if ( command_line_pos > 0 )     {
679                                 command_line[--command_line_pos] = 0;
680                         }
681                         break;
682
683                 case SDLK_F3:
684                         if ( last_oldcommand > -1 )     {
685                                 SDL_strlcpy( command_line, oldcommand_line[last_oldcommand], SDL_arraysize(command_line) );
686                                 command_line_pos = strlen(command_line);
687                                 command_line[command_line_pos] = 0;
688                         }
689                         break;
690
691                 case SDLK_UP:
692                         command_scroll--;
693                         if (command_scroll<0) 
694                                 command_scroll = last_oldcommand;
695
696                         if ( command_scroll > -1 )      {
697                                 SDL_strlcpy( command_line, oldcommand_line[command_scroll], SDL_arraysize(command_line) );
698                                 command_line_pos = strlen(command_line);
699                                 command_line[command_line_pos] = 0;
700                         }
701                         break;
702
703                 case SDLK_DOWN:
704                         command_scroll++;
705                         if (command_scroll>last_oldcommand) 
706                                 command_scroll = 0;
707                         if (command_scroll>last_oldcommand) 
708                                 command_scroll = -1;
709                         if ( command_scroll > -1 )      {
710                                 SDL_strlcpy( command_line, oldcommand_line[command_scroll], SDL_arraysize(command_line) );
711                                 command_line_pos = strlen(command_line);
712                                 command_line[command_line_pos] = 0;
713                         }
714                         break;
715
716                 case SDLK_RETURN:       {
717                         debug_output( '\n' );
718                         debug_draw();
719
720                         debug_do_command(command_line);
721
722                         int i, found = 0;
723                         for (i=0; i<=last_oldcommand; i++ )     {
724                                 if (!SDL_strcasecmp( oldcommand_line[i], command_line ))        {
725                                         found = 1;
726                                 }
727                         }
728                         if ( !found )   {
729                                 if ( last_oldcommand < DEBUG_HISTORY-1 )        {
730                                         last_oldcommand++;
731                                         SDL_strlcpy( oldcommand_line[last_oldcommand], command_line, SDL_arraysize(oldcommand_line[0]) );
732                                 } else {
733                                         for (i=0; i<last_oldcommand; i++ )      {
734                                                 SDL_strlcpy( oldcommand_line[i], oldcommand_line[i+1], SDL_arraysize(oldcommand_line[0]) );
735                                         }
736                                         SDL_strlcpy( oldcommand_line[last_oldcommand], command_line, SDL_arraysize(oldcommand_line[0]) );
737                                 }
738                         }
739 //                      int i;
740 //                      for (i=0; i<=last_oldcommand; i++ )     {
741 //                              dc_printf( "OC %d. %s\n", i, oldcommand_line[i] );
742 //                      }
743         
744                         debug_output( '\n' );
745                         command_line_pos = 0;
746                         command_line[command_line_pos] = 0;
747
748                         command_scroll = 0;
749
750                         } 
751                         break;
752                 default:        {
753                                 int c = key_get_text_input();
754                                 if ( (c >= 0) && (c < 255) ) {
755                                         command_line[command_line_pos++] = (ubyte)c;
756                                         command_line[command_line_pos] = 0;
757                                 }
758                         }
759                         break;
760
761                 }
762
763                 SDL_strlcpy( debug_text[debug_y], ">", DCOLS );
764                 SDL_strlcat( debug_text[debug_y], command_line, DCOLS );
765                 debug_draw();
766
767                 if ( _func ){
768                         _func();
769                 }
770         }
771
772         while( key_inkey() ){
773                 os_poll();
774         }
775 }
776
777 void debug_help()
778 {
779         int s, i;
780
781         dc_printf( "Available functions:\n\n" );        
782
783         s = scroll_times;
784         for (i=0; i<Num_debug_commands; i++ )   {
785                 dc_printf( " %s - %s\n", Debug_command[i]->name, Debug_command[i]->help );
786                 //mprintf(( "Scroll times %d\n", scroll_times - s ));
787                 if ( scroll_times - s > DROWS - 3 )     {
788                         int k;
789                         dc_printf( "       Press a key...B for back\n" );
790                         debug_draw();
791                         k = key_getch();
792                         s = scroll_times;
793                         if ( k == SDLK_b )  {
794                                 i -= ((DROWS-3)*2);
795                                 if ( i <= 0 )
796                                         i = -1;
797                         }
798                 } 
799                 debug_draw();
800         }
801         dc_printf( "\n" );
802
803         dc_printf( "Typing '? function_name' will give the current status.\n" );
804         dc_printf( "Typing 'function_name ?' will give help on the function.\n" );
805         dc_printf( "Typing ? or help will give you help.\n");
806         dc_printf( "F3 selects last command line.\n" );
807 }
808