]> icculus.org git repositories - taylor/freespace2.git/blob - src/debugconsole/console.cpp
fix repeating key input
[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 <setjmp.h>
110 #include <string.h>
111
112 #include "pstypes.h"
113 #include "freespace.h"
114 #include "font.h"
115 #include "timer.h"
116 #include "2d.h"
117 #include "key.h"
118 #include "alphacolors.h"
119 #include "osapi.h"
120
121 #define MAX_COMMANDS 300
122
123 static int Num_debug_commands = 0;
124 static debug_command *Debug_command[MAX_COMMANDS];
125
126
127 debug_command::debug_command(const char *_name, const char *_help, void (*_func)() )
128 {
129         int i;
130
131         if ( Num_debug_commands >= MAX_COMMANDS )       {
132                 Int3();                 // Too many debug console commands!! Increase MAX_COMMANDS!!
133                 return;
134         }
135
136         for (i=0; i<Num_debug_commands; i++ )   {
137                 int ret  = stricmp( Debug_command[i]->name, _name );
138
139                 if ( ret == 0)  {
140                         Int3();         // This debug console command already exists!!!! 
141                         return;
142                 } else if ( ret > 0 )   {
143                         break;          // Insert it here
144
145                 } else if ( ret < 0 )   {
146                         // do nothing
147                 }
148         }
149
150         if ( i < Num_debug_commands )   {
151                 // Insert it at element i
152                 int j;
153                 for (j=Num_debug_commands; j>i; j-- )   {
154                         Debug_command[j] = Debug_command[j-1];
155                 }
156                 Debug_command[i] = this;                
157                 Num_debug_commands++;
158         } else {
159                 Debug_command[Num_debug_commands] = this;               
160                 Num_debug_commands++;
161         }
162
163         name = _name;
164         help = _help;
165         func = _func;
166 }
167
168 // some global variables
169 int Dc_command; // If this is set, then process the command
170 int Dc_help;            // If this is set, then print out the help text in the form, "usage: ... \nLong description\n" );
171 int Dc_status;          // If this is set, then print out the current status of the command.
172 char *Dc_arg;           // The (lowercased) string value of the argument retrieved from dc_arg
173 char *Dc_arg_org;       // Dc_arg before it got converted to lowercase
174 uint Dc_arg_type;       // The type of dc_arg.
175 const char *Dc_command_line;            // The rest of the command line, from the end of the last processed arg on.
176 int Dc_arg_int;         // If Dc_arg_type & ARG_INT is set, then this is the value
177 float Dc_arg_float;     // If Dc_arg_type & ARG_FLOAT is set, then this is the value
178
179 int scroll_times = 0;           // incremented each time display scrolls
180
181 int debug_inited = 0;
182
183 #define DROWS 25
184 #define DCOLS 80
185
186 int debug_x=0, debug_y=0;
187 char debug_text[DROWS][DCOLS];
188
189
190 static char command_line[1024];
191 static int command_line_pos = 0;
192 #define DEBUG_HISTORY 16
193 static char oldcommand_line[DEBUG_HISTORY][1024];
194 int last_oldcommand=-1;
195 int command_scroll = 0;
196
197 ///=========================== SCANNER =======================
198 typedef enum {
199         LETTER, QUOTE, SPECIAL, EOF_CODE, DIGIT,
200 } CHAR_CODE;
201
202 typedef enum {
203         NO_TOKEN, IDENTIFIER, NUMBER, STRING, 
204 } TOKEN_CODE;
205
206
207 #define MAX_TOKEN_STRING_LENGTH 128
208
209 char                    scanner_ch;
210 TOKEN_CODE      scanner_token;
211
212 char scanner_token_string[MAX_TOKEN_STRING_LENGTH];
213 char scanner_word_string[MAX_TOKEN_STRING_LENGTH];
214 const char * scanner_bufferp = "";
215 char * scanner_tokenp = scanner_token_string;
216
217 CHAR_CODE scanner_char_table[256];
218
219 #define scanner_char_code(x) scanner_char_table[x]
220
221 void scanner_get_char()
222 {
223         if ( *scanner_bufferp == '\0' ) {
224                 scanner_ch = 0;
225                 return;
226         }
227         scanner_ch = *scanner_bufferp++;
228 }
229
230 void scanner_init()
231 {
232         int ch;
233         for (ch=0; ch<256; ++ch) scanner_char_table[ch] = SPECIAL;
234         for (ch='0'; ch<='9'; ++ch) scanner_char_table[ch] = DIGIT;
235         for (ch='A'; ch<='Z'; ++ch) scanner_char_table[ch] = LETTER;
236         for (ch='a'; ch<='z'; ++ch) scanner_char_table[ch] = LETTER;
237
238         scanner_char_table[(int)'.'] = DIGIT;
239         scanner_char_table[(int)'-'] = DIGIT;
240         scanner_char_table[(int)'+'] = DIGIT;
241         
242         scanner_char_table[(int)'_'] = LETTER;
243         scanner_char_table[34] = QUOTE;
244         scanner_char_table[0] = EOF_CODE;
245
246
247         scanner_char_table[(int)':'] = LETTER;
248         scanner_char_table[(int)'\\'] = LETTER;
249
250         scanner_ch = 0;
251 }
252
253
254 void scanner_skip_blanks()
255 {
256         while( (scanner_ch ==' ') || (scanner_ch =='\t') ) 
257                 scanner_get_char();
258 }
259
260
261 void scanner_downshift_word()
262 {
263         int offset = 'a' - 'A';
264         char * tp;
265
266         strcpy( scanner_word_string, scanner_token_string );
267         
268         tp = scanner_word_string;
269         do {
270                 *tp = (char)((*tp>='A') && (*tp <='Z') ? *tp + offset : *tp) ;
271                 tp++;
272         } while (*tp != '\0' );
273 }
274
275
276 void scanner_get_word()
277 {
278         while( (scanner_char_code((int)scanner_ch)==LETTER) || (scanner_char_code((int)scanner_ch)==DIGIT)  )   {
279                 *scanner_tokenp++ = scanner_ch;
280                 scanner_get_char();
281         }
282         *scanner_tokenp = '\0';
283
284         scanner_token = IDENTIFIER;
285 }
286
287
288 void scanner_get_string()
289 {
290         *scanner_tokenp++ = 34;
291         scanner_get_char();
292
293         while(scanner_ch != 34 )        {
294                 *scanner_tokenp++ = scanner_ch;
295                 scanner_get_char();
296         }
297         scanner_get_char();
298         *scanner_tokenp++ = 34;
299         *scanner_tokenp = '\0';
300         scanner_token = STRING;
301 }
302
303
304
305 void scanner_get_token()
306 {
307         scanner_skip_blanks();
308         scanner_tokenp = scanner_token_string;
309         *scanner_tokenp = 0;
310
311
312         switch( scanner_char_code((int)scanner_ch) )    {
313         case QUOTE:             scanner_get_string();   break;
314         case EOF_CODE:  scanner_token = NO_TOKEN;       break;
315         case DIGIT:
316         case LETTER:    scanner_get_word(); break;
317         default:                        
318                 *scanner_tokenp++ = scanner_ch;
319                 *scanner_tokenp = '\0';
320                 scanner_get_char();
321                 scanner_token = IDENTIFIER;
322                 break;
323         }
324
325         scanner_downshift_word();
326 }
327
328 void scanner_start_command( const char * s )
329 {
330         scanner_bufferp = s;
331         scanner_get_char();
332 }
333
334
335 int Dc_debug_on = 0;
336 jmp_buf dc_bad_arg;
337
338 void dc_get_arg(uint type)
339 {
340         scanner_get_token();
341
342         Dc_command_line = scanner_bufferp;      
343         Dc_arg_org = scanner_token_string;
344         Dc_arg = scanner_word_string;
345
346         if (Dc_debug_on)        {
347                 dc_printf( "next arg is '%s', was originally '%s'\n", Dc_arg, Dc_arg_org );
348                 dc_printf( "Rest of the command line is '%s'\n", Dc_command_line );
349         }
350         
351         if ( scanner_token == NO_TOKEN )        {
352                 Dc_arg_type = ARG_NONE;
353         } else if ( scanner_token == IDENTIFIER )       {
354                 Dc_arg_type = ARG_STRING;
355         } else if ( scanner_token == STRING )   {
356                 Dc_arg_type = ARG_QUOTE;
357         } else {
358                 Dc_arg_type = ARG_STRING;
359         }
360
361         if ( Dc_arg_type & ARG_STRING ) {
362                 int i, num_digits, len;
363
364                 len = strlen(Dc_arg);
365                 num_digits = 0;
366
367                 for (i=0; i<len; i++)
368                         if ( scanner_char_table[(int)Dc_arg[i]] == DIGIT ) num_digits++;
369
370                 if ( num_digits==len )  {
371                         Dc_arg_type |= ARG_FLOAT;
372                         Dc_arg_float = (float)atof(Dc_arg);
373                         if ( !strchr( Dc_arg, '.' ))    {
374                                 Dc_arg_type |= ARG_INT;
375                                 Dc_arg_int = atoi(Dc_arg);
376                         }
377                 } else {
378                         if ( (Dc_arg[0] == '0') && (Dc_arg[1] == 'x') ) {
379                                 char *p;
380                                 int n;
381                                 n = strtol(Dc_arg,&p,0);
382                                 if ( *p == 0 )  {
383                                         Dc_arg_type |= ARG_INT|ARG_HEX;
384                                         Dc_arg_int = n;
385                                 }
386                         } 
387                 }
388
389                 if (Dc_debug_on)        {
390                         if ( Dc_arg_type & ARG_FLOAT )
391                                 dc_printf( "Found float number! %f\n", Dc_arg_float );
392
393                         if ( Dc_arg_type & ARG_INT )
394                                 dc_printf( "Found int number! %d\n", Dc_arg_int );
395
396                         if ( Dc_arg_type & ARG_HEX )
397                                 dc_printf( "Found hex number! 0x%x\n", Dc_arg_int );
398                 }
399
400                 if ( !stricmp( Dc_arg, "on" ))
401                         Dc_arg_type |= ARG_TRUE;
402                 if ( !stricmp( Dc_arg, "true" ))
403                         Dc_arg_type |= ARG_TRUE;
404                 if ( !stricmp( Dc_arg, "off" ))
405                         Dc_arg_type |= ARG_FALSE;
406                 if ( !stricmp( Dc_arg, "false" ))
407                         Dc_arg_type |= ARG_FALSE;
408
409                 if ( !stricmp( Dc_arg, "+" ))
410                         Dc_arg_type |= ARG_PLUS;
411
412                 if ( !stricmp( Dc_arg, "-" ))
413                         Dc_arg_type |= ARG_MINUS;
414
415                 if ( !stricmp( Dc_arg, "," ))
416                         Dc_arg_type |= ARG_COMMA;
417         }
418
419         if ( Dc_arg_type & ARG_INT)     {
420                 if ( Dc_arg_int )       
421                         Dc_arg_type |= ARG_TRUE;
422                 else
423                         Dc_arg_type |= ARG_FALSE;
424         }
425
426         if ( !(Dc_arg_type&type) )      {
427                 if ( (Dc_arg_type & ARG_NONE) && !(type & ARG_NONE))    
428                         dc_printf( "Error: Not enough parameters.\n" );
429                 else
430                         dc_printf( "Error: '%s' invalid type\n", Dc_arg );
431                 longjmp(dc_bad_arg,1);
432         }
433
434 }
435
436 void debug_help();
437
438 void debug_do_command(const char * command)
439 {
440
441         int i;
442         int mode = 0;
443
444         if ( strlen(command) < 1 ) return;
445         
446         Dc_debug_on = 0;
447         Dc_command_line = command;
448         scanner_start_command(command);
449
450         if (setjmp(dc_bad_arg) )        {
451                 return;
452         }
453         
454         dc_get_arg( ARG_ANY );
455
456         if ( !strcmp( Dc_arg, "debug" ) )       {
457                 Dc_debug_on = 1;
458                 dc_printf( "Command line: '%s'\n", Dc_command_line );
459                 dc_get_arg( ARG_ANY );
460         }
461
462         if ( !strcmp( Dc_arg, "?" ) )   {
463                 mode = 1;
464                 dc_get_arg( ARG_ANY );
465
466                 if ( Dc_arg_type&ARG_NONE )     {
467                         debug_help();           
468                         return;
469                 }
470         }
471
472         if ( !strcmp( Dc_arg, "help" ) || !strcmp( Dc_arg, "man" ) )    {
473                 mode = 2;
474                 dc_get_arg( ARG_ANY );
475                 if ( Dc_arg_type&ARG_NONE )     {
476                         debug_help();           
477                         return;
478                 }
479         }
480
481         if ( strstr( Dc_command_line, "?" ) )   {
482                 mode = 2;
483         }
484
485         if ( !(Dc_arg_type&ARG_STRING) )        {
486                 dc_printf( "Invalid keyword '%s'\n", Dc_arg );
487                 return;
488         }
489
490
491         if (Dc_debug_on)        {
492                 dc_printf( "Searching for command '%s'\n", Dc_arg );
493         }
494
495         for (i=0; i<Num_debug_commands; i++ )   {
496                 if ( !stricmp( Debug_command[i]->name, Dc_arg ))        {
497                 
498                         if (mode==0)    {
499                                 if (Dc_debug_on)        
500                                         dc_printf( "Calling function '%s'\n", Dc_arg );
501                                 Dc_command = 1;
502                                 Dc_help = 0;
503                                 Dc_status = 1;
504                         } else if (mode==1) {
505                                 if (Dc_debug_on)        
506                                         dc_printf( "Checking status for '%s'\n", Dc_arg );
507                                 Dc_command = 0;
508                                 Dc_help = 0;
509                                 Dc_status = 1;
510                         } else {
511                                 if (Dc_debug_on)        
512                                         dc_printf( "Doing help for '%s'\n", Dc_arg );
513                                 Dc_command = 0;
514                                 Dc_help = 1;
515                                 Dc_status = 0;
516                         }
517
518                         (*Debug_command[i]->func)();
519
520                         if (mode==0)    {
521                                 dc_get_arg(ARG_ANY);
522                                 if (!(Dc_arg_type&ARG_NONE))    {
523                                         dc_printf( "Ignoring the unused command line tail '%s %s'\n", Dc_arg_org, Dc_command_line );
524                                 }
525                         }
526
527                         return;
528                 }
529         }
530
531         dc_printf( "Unknown command '%s'\n", Dc_arg );
532 }
533
534 void debug_draw()
535 {
536         int i;
537         
538         gr_clear();
539         gr_set_font(FONT1);
540         gr_set_color_fast( &Color_bright );
541         gr_string( 0x8000, 3, "Debug Console" );
542
543         gr_set_color_fast( &Color_normal );
544
545         for (i=0; i<DROWS; i++ )        {
546                 gr_string( 0, i*16+16, debug_text[i] );
547         }
548
549         int t = timer_get_fixed_seconds() / (F1_0/3);
550         if ( t & 1 )    {
551                 int w,h;
552                 char c;
553
554                 c = debug_text[debug_y][command_line_pos+1];
555                 debug_text[debug_y][command_line_pos+1] = 0;
556
557                 gr_get_string_size( &w, &h, debug_text[debug_y] );
558                 
559                 //gr_string( w, debug_y*16, "_" );
560                 gr_rect(w+1,debug_y*16+1+16,2,14);
561         
562                 debug_text[debug_y][command_line_pos+1] = c;
563         }
564
565         gr_flip();
566 }
567
568
569 void debug_output( char c )
570 {
571         if ( c == '\t' )        {
572                 int next_tab = ((debug_x/28)+1)*28;
573
574                 if ( next_tab >= DCOLS-1 )      {
575                         debug_x=0;
576                         debug_y++;
577                         scroll_times++;
578                         if ( debug_y >= DROWS ) {
579                                 int i;
580                                 for (i=1; i<DROWS; i++ )
581                                         strcpy( debug_text[i-1], debug_text[i] );
582                                 debug_y = DROWS-1;
583                                 debug_x = 0;
584                                 debug_text[debug_y][debug_x] = 0;
585                         }
586                         debug_text[debug_y][debug_x] = 0;
587                         return;
588                 }
589         
590                 for ( ; debug_x < next_tab; )
591                         debug_text[debug_y][debug_x++] = ' ';
592                 debug_text[debug_y][debug_x] = 0;
593                 return;
594         }
595
596         if ( (c == '\n') || (debug_x >= DCOLS-1) )      {
597                 debug_x=0;
598                 debug_y++;
599                 scroll_times++;
600                 if ( debug_y >= DROWS ) {
601                         int i;
602                         for (i=1; i<DROWS; i++ )
603                                 strcpy( debug_text[i-1], debug_text[i] );
604                         debug_y = DROWS-1;
605                         debug_x = 0;
606                         debug_text[debug_y][debug_x] = 0;
607                 }
608                 debug_text[debug_y][debug_x] = 0;
609                 if ( c == '\n' ) return;
610         }
611
612         debug_text[debug_y][debug_x++] = c;
613         debug_text[debug_y][debug_x] = 0;
614 }
615
616 void dc_printf(const char *format, ...)
617 {
618         char tmp[DCOLS*2];
619         va_list args;
620         
621         va_start(args, format);
622         vsprintf(tmp, format, args);
623         va_end(args);
624
625         char *p = tmp;
626         while( *p )     {
627                 debug_output(*p);
628                 p++;
629         } 
630 }
631
632
633
634 void debug_init()
635 {
636         int i;
637         if ( debug_inited ) return;
638
639         debug_inited = 1;
640
641         debug_x=0;
642         debug_y=0;
643
644         for (i=0; i<DROWS; i++ )        {
645                 debug_text[i][0] = 0;
646         }
647         
648         dc_printf("Debug console started.\n" );
649 }
650
651
652 void debug_console( void (*_func)() )
653 {
654         int done = 0;
655
656         scanner_init();
657
658         while( key_inkey() ){
659                 os_poll();
660         }
661
662         if ( !debug_inited ) debug_init();
663
664
665         debug_draw();
666         
667         while (!done)   {
668                 // poll the os
669                 os_poll();
670
671                 int k = key_inkey();
672                 switch( k )     {
673
674                 case KEY_SHIFTED+SDLK_RETURN:
675                 case SDLK_ESCAPE:
676                         done=1; break;
677
678                 case SDLK_BACKSPACE:
679                         if ( command_line_pos > 0 )     {
680                                 command_line[--command_line_pos] = 0;
681                         }
682                         break;
683
684                 case SDLK_F3:
685                         if ( last_oldcommand > -1 )     {
686                                 strcpy( command_line, oldcommand_line[last_oldcommand] );
687                                 command_line_pos = strlen(command_line);
688                                 command_line[command_line_pos] = 0;
689                         }
690                         break;
691
692                 case SDLK_UP:
693                         command_scroll--;
694                         if (command_scroll<0) 
695                                 command_scroll = last_oldcommand;
696
697                         if ( command_scroll > -1 )      {
698                                 strcpy( command_line, oldcommand_line[command_scroll] );
699                                 command_line_pos = strlen(command_line);
700                                 command_line[command_line_pos] = 0;
701                         }
702                         break;
703
704                 case SDLK_DOWN:
705                         command_scroll++;
706                         if (command_scroll>last_oldcommand) 
707                                 command_scroll = 0;
708                         if (command_scroll>last_oldcommand) 
709                                 command_scroll = -1;
710                         if ( command_scroll > -1 )      {
711                                 strcpy( command_line, oldcommand_line[command_scroll] );
712                                 command_line_pos = strlen(command_line);
713                                 command_line[command_line_pos] = 0;
714                         }
715                         break;
716
717                 case SDLK_RETURN:       {
718                         debug_output( '\n' );
719                         debug_draw();
720
721                         debug_do_command(command_line);
722
723                         int i, found = 0;
724                         for (i=0; i<=last_oldcommand; i++ )     {
725                                 if (!stricmp( oldcommand_line[i], command_line ))       {
726                                         found = 1;
727                                 }
728                         }
729                         if ( !found )   {
730                                 if ( last_oldcommand < DEBUG_HISTORY-1 )        {
731                                         last_oldcommand++;
732                                         strcpy( oldcommand_line[last_oldcommand], command_line);
733                                 } else {
734                                         int i;
735                                         for (i=0; i<last_oldcommand; i++ )      {
736                                                 strcpy( oldcommand_line[i], oldcommand_line[i+1] );
737                                         }
738                                         strcpy( oldcommand_line[last_oldcommand], command_line);
739                                 }
740                         }
741 //                      int i;
742 //                      for (i=0; i<=last_oldcommand; i++ )     {
743 //                              dc_printf( "OC %d. %s\n", i, oldcommand_line[i] );
744 //                      }
745         
746                         debug_output( '\n' );
747                         command_line_pos = 0;
748                         command_line[command_line_pos] = 0;
749
750                         command_scroll = 0;
751
752                         } 
753                         break;
754                 default:        {
755                                 int c = key_get_text_input();
756                                 if ( (c >= 0) && (c < 255) ) {
757                                         command_line[command_line_pos++] = (ubyte)c;
758                                         command_line[command_line_pos] = 0;
759                                 }
760                         }
761                         break;
762
763                 }
764
765                 strcpy( debug_text[debug_y], ">" );
766                 strcat( debug_text[debug_y], command_line );
767                 debug_draw();
768
769                 if ( _func ){
770                         _func();
771                 }
772         }
773
774         while( key_inkey() ){
775                 os_poll();
776         }
777 }
778
779 void debug_help()
780 {
781         int s, i;
782
783         dc_printf( "Available functions:\n\n" );        
784
785         s = scroll_times;
786         for (i=0; i<Num_debug_commands; i++ )   {
787                 dc_printf( " %s - %s\n", Debug_command[i]->name, Debug_command[i]->help );
788                 //mprintf(( "Scroll times %d\n", scroll_times - s ));
789                 if ( scroll_times - s > DROWS - 3 )     {
790                         int k;
791                         dc_printf( "       Press a key...B for back\n" );
792                         debug_draw();
793                         k = key_getch();
794                         s = scroll_times;
795                         if ( k == SDLK_b )  {
796                                 i -= ((DROWS-3)*2);
797                                 if ( i <= 0 )
798                                         i = -1;
799                         }
800                 } 
801                 debug_draw();
802         }
803         dc_printf( "\n" );
804
805         dc_printf( "Typing '? function_name' will give the current status.\n" );
806         dc_printf( "Typing 'function_name ?' will give help on the function.\n" );
807         dc_printf( "Typing ? or help will give you help.\n");
808         dc_printf( "F3 selects last command line.\n" );
809 }
810