Skip to content

Commit

Permalink
end app on bdos read console buffer ^c + cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
davidly committed Aug 14, 2023
1 parent c4edf1c commit 037b69a
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 50 deletions.
132 changes: 87 additions & 45 deletions djl_con.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,66 @@ class ConsoleConfiguration
HANDLE consoleInputHandle;
WINDOWPLACEMENT oldWindowPlacement;
CONSOLE_SCREEN_BUFFER_INFOEX oldScreenInfo;
DWORD oldConsoleMode;
DWORD oldOutputConsoleMode, oldInputConsoleMode;
CONSOLE_CURSOR_INFO oldCursorInfo;
int16_t setWidth;
UINT oldOutputCP;
#else
bool initialized;
bool established;
#ifndef OLDGCC // the several-years-old Gnu C compiler for the RISC-V development boards
struct termios orig_termios;
#endif
#endif

bool inputEstablished, outputEstablished;

void EstablishConsoleInput()
{
if ( inputEstablished )
return;

#ifdef _MSC_VER
GetConsoleMode( consoleOutputHandle, &oldInputConsoleMode );
DWORD dwMode = oldInputConsoleMode;
dwMode &= ~ENABLE_PROCESSED_INPUT;
SetConsoleMode( consoleInputHandle, dwMode );
tracer.Trace( "old and new console input mode: %#x, %#x\n", oldInputConsoleMode, dwMode );
#else
#ifndef OLDGCC // the several-years-old Gnu C compiler for the RISC-V development boards. that machine has no keyboard support
tcgetattr( 0, &orig_termios );

// make input raw so it's possible to peek to see if a keystroke is available

struct termios new_termios;
memcpy( &new_termios, &orig_termios, sizeof( new_termios ) );

cfmakeraw( &new_termios );
new_termios.c_oflag = orig_termios.c_oflag;
tcsetattr( 0, TCSANOW, &new_termios );
#endif
#endif

inputEstablished = true;
} //EstablishConsoleInput

public:
#ifdef _MSC_VER
ConsoleConfiguration() : consoleOutputHandle( 0 ), consoleInputHandle( 0 ), oldConsoleMode( 0 ), setWidth( 0 ), oldOutputCP( 0 )
ConsoleConfiguration() : oldOutputConsoleMode( 0 ), oldInputConsoleMode( 0 ),
setWidth( 0 ), oldOutputCP( 0 ),
inputEstablished( false ), outputEstablished( false )
{
oldWindowPlacement = {0};
oldScreenInfo = {0};
oldCursorInfo = {0};

consoleOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
consoleInputHandle = GetStdHandle( STD_INPUT_HANDLE );

EstablishConsoleInput();
} //ConsoleConfiguration
#else
ConsoleConfiguration() : initialized( false ), established( false )
ConsoleConfiguration() : inputEstablished( false ), outputEstablished( false )
{
#ifndef OLDGCC // the several-years-old Gnu C compiler for the RISC-V development boards
tcgetattr( 0, &orig_termios );

// make input raw so it's possible to peek to see if a keystroke is available

struct termios new_termios;
memcpy( &new_termios, &orig_termios, sizeof( new_termios ) );

cfmakeraw( &new_termios );
new_termios.c_oflag = orig_termios.c_oflag;
tcsetattr( 0, TCSANOW, &new_termios );
#endif

initialized = true;
EstablishConsoleInput();
} //ConsoleConfiguration
#endif

Expand All @@ -57,12 +80,11 @@ class ConsoleConfiguration
RestoreConsole();
}

bool IsOutputEstablished() { return outputEstablished; }

#ifdef _MSC_VER
bool IsEstablished() { return ( 0 != consoleOutputHandle ); }
HANDLE GetOutputHandle() { return consoleOutputHandle; };
HANDLE GetInputHandle() { return consoleInputHandle; };
#else
bool IsEstablished() { return established; }
#endif

void SetCursorInfo( uint32_t size ) // 0 to 100
Expand All @@ -87,14 +109,13 @@ class ConsoleConfiguration
#endif
} //SetCursorInfo

void EstablishConsole( int16_t width = 80, int16_t height = 24, void * proutine = 0 )
void EstablishConsoleOutput( int16_t width = 80, int16_t height = 24, void * proutine = 0 )
{
if ( outputEstablished )
return;

#ifdef _MSC_VER
if ( 0 != consoleOutputHandle )
return;

consoleOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
consoleInputHandle = GetStdHandle( STD_INPUT_HANDLE );
GetConsoleCursorInfo( consoleOutputHandle, &oldCursorInfo );

if ( 0 != width )
Expand Down Expand Up @@ -144,27 +165,33 @@ class ConsoleConfiguration

DWORD dwMode = 0;
GetConsoleMode( consoleOutputHandle, &dwMode );
oldConsoleMode = dwMode;
oldOutputConsoleMode = dwMode;
dwMode |= ( ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_WINDOW_INPUT );
tracer.Trace( "old console mode: %04x, new mode: %04x\n", oldConsoleMode, dwMode );
tracer.Trace( "old console mode: %04x, new mode: %04x\n", oldOutputConsoleMode, dwMode );
SetConsoleMode( consoleOutputHandle, dwMode );

// don't automatically have ^c terminate the app. ^break will still terminate the app

PHANDLER_ROUTINE handler = (PHANDLER_ROUTINE) proutine;
SetConsoleCtrlHandler( handler, TRUE );
#else
established = true;
#endif

outputEstablished = true;

if ( 0 != width )
SendClsSequence();
} //EstablishConsole
} //EstablishConsoleOutput

void RestoreConsole( bool clearScreen = true )
{
#ifdef _MSC_VER
if ( 0 != consoleOutputHandle )
if ( inputEstablished )
{
SetConsoleMode( consoleInputHandle, oldInputConsoleMode );
inputEstablished = false;
}

if ( outputEstablished )
{
if ( clearScreen )
SendClsSequence();
Expand All @@ -178,23 +205,23 @@ class ConsoleConfiguration
SetWindowPlacement( GetConsoleWindow(), & oldWindowPlacement );
}

SetConsoleMode( consoleOutputHandle, oldConsoleMode );
consoleOutputHandle = 0;
SetConsoleMode( consoleOutputHandle, oldOutputConsoleMode );
outputEstablished = false;
}
#else
if ( initialized )
if ( inputEstablished )
{
#ifndef OLDGCC // the several-years-old Gnu C compiler for the RISC-V development boards
tcsetattr( 0, TCSANOW, &orig_termios );
#endif
initialized = false;
inputEstablished = false;
}

if ( established )
if ( outputEstablished )
{
if ( clearScreen )
SendClsSequence();
established = false;
outputEstablished = false;
}
#endif
} //RestoreConsole
Expand Down Expand Up @@ -229,15 +256,19 @@ class ConsoleConfiguration

static int portable_kbhit()
{
int result = 0;

#ifdef _MSC_VER
return _kbhit();
result = _kbhit();
#else
fd_set set;
FD_ZERO( &set );
FD_SET( STDIN_FILENO, &set );
struct timeval timeout = {0};
return ( select( 1, &set, NULL, NULL, &timeout ) > 0 );
result = ( select( 1, &set, NULL, NULL, &timeout ) > 0 );
#endif

return result;
} //portable_kbhit

static int portable_getch()
Expand Down Expand Up @@ -311,12 +342,23 @@ class ConsoleConfiguration
return buf;
} //portable_gets_s

static char * cpm_read_console( char * buf, size_t bufsize, uint8_t & out_len )
static int cpm_read_console( char * buf, size_t bufsize, uint8_t & out_len )
{
char ch;
out_len = 0;
do
{
char ch = (char) portable_getch();
ch = (char) portable_getch();
tracer.Trace( " cpm_read_console read character %02x\n", ch );

// CP/M read console buffer treats these control characters as special: c, e, h, i, j, m, p, r, s, u, x
// per https://techtinkering.com/articles/cpm-standard-console-control-characters/
// Only c, h, j, and m are currently handled correctly.
// ^c means exit the currently running app in CP/M

if ( 3 == ch )
return ch;

if ( '\n' == ch || '\r' == ch )
{
printf( "\r" );
Expand Down Expand Up @@ -344,7 +386,7 @@ class ConsoleConfiguration
}
} while( true );

return buf;
return ch; // return the last character read
} //cpm_read_console
}; //ConsoleConfiguration

19 changes: 14 additions & 5 deletions ntvcm.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,10 @@ void output_character( uint8_t c )
// for terminal emulation, I only implement translations for actual sequences apps use.
// if the output character is ESC, assume the app wants 80x24.

if ( 0x1b == c && !g_forceConsole && !g_consoleConfig.IsEstablished() )
if ( 0x1b == c && !g_forceConsole && !g_consoleConfig.IsOutputEstablished() )
{
tracer.Trace( " establishing 80x24\n" );
g_consoleConfig.EstablishConsole( 80, 24 );
g_consoleConfig.EstablishConsoleOutput( 80, 24 );
}

if ( g_kayproToCP437 )
Expand Down Expand Up @@ -845,6 +845,7 @@ uint8_t x80_invoke_hook()
// conin

uint8_t input = (uint8_t) ConsoleConfiguration::portable_getch();
tracer.Trace( " conin got %02xh from getch()\n", input );
reg.a = map_input( input );
tracer.Trace( " conin is returning %02xh\n", reg.a );
}
Expand Down Expand Up @@ -906,6 +907,7 @@ uint8_t x80_invoke_hook()
case 2:
{
// console output
// CP/M checks for a ^c from the keyboard and end the application if found. This code doesn't do that yet.

uint8_t ch = reg.e;
if ( 0x0d != ch ) // skip carriage return because line feed turns into cr+lf
Expand Down Expand Up @@ -979,9 +981,10 @@ uint8_t x80_invoke_hook()
}
case 9:
{
// print string terminated by a dollar sign $. string is pointed to by DE

uint16_t i = reg.D();
uint32_t count = 0;

//tracer.TraceBinaryData( memory + i, 0x20, 0 );

while ( '$' != memory[i] )
Expand Down Expand Up @@ -1017,7 +1020,13 @@ uint8_t x80_invoke_hook()
{
pbuf[ 2 ] = 0;
uint8_t out_len;
ConsoleConfiguration::cpm_read_console( pbuf + 2, in_len, out_len );
char last = ConsoleConfiguration::cpm_read_console( pbuf + 2, in_len, out_len );
if ( 3 == last )
{
tracer.Trace( " bdos read console buffer read a ^c, so it's terminating the app\n" );
return OPCODE_HLT;
}

pbuf[ 1 ] = out_len;

tracer.Trace( " read console len %u, string '%.*s'\n", out_len, (size_t) out_len, pbuf + 2 );
Expand Down Expand Up @@ -2298,7 +2307,7 @@ int main( int argc, char * argv[] )
}

if ( force80x24 )
g_consoleConfig.EstablishConsole( 80, 24 );
g_consoleConfig.EstablishConsoleOutput( 80, 24 );

uint64_t total_cycles = 0;
CPUCycleDelay delay( clockrate );
Expand Down

0 comments on commit 037b69a

Please sign in to comment.