Subversion Repositories svn1-original

Rev

Rev 61 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*************************************************************************
*           Copyright (C) 1995 Embedded Solutions
*                       All rights reserved
*
* file:     src\vduW32.c
*
* purpose:  This module contains all the VDU interface routines
*
*           This instance of this file implements the functions
*           in a Win32 platform.
*
*           A small number of routines are provided. These can be emulated
*           on other machines to provide similar functions
*
*           A number of general purpose I/O routines are also provided
*
* functions
*       init_screen             - Initialize the screen
*       cur                     - Position the cursor on the screen
*       clearscreen             - Clears the vdu screen
*       beep                    - Generate a bell character
*       flush_out               - Flush terminal output
*       getinp                  - Get one character of input
*       getnum                  - Get a number from the operator
*       getstring               - Get and edit a string
*       getsex                  - Get a sex type from the operator
*       getclass                - Get a class descriptor
*       getcountry              - Get a country descriptor
*       getfnc                  - Get menu selector
*       getyes                  - Prompt for YES / NO
*       to_upper                - Convert character to upper case
*       to_lower                - Convert character to lower case
*       sleep                   - Wait a bit
*       printf                  - Text display routines
*       putchar                 - Text display routines
*       console_clreol          - Clear to end of the line
*       console_prompt          - Display a hightlighted prompt
*
* programmer: David Purdie
*
* revision  date        by      reason
*   00.0    17/09/2002  DDP     Created
*
**************************************************************************/

#include    <stdio.h>
#include    <ctype.h>
#include    <windows.h>
#include    <wincon.h>

#include    "consts.h"
#include    "structs.h"
#include    "proto.h"

/* variables used by the routines */

int         n_lines;                             /* Number of lines on the screen */
int         n_cols;

int         rubout = '\010';                     /* users rubout character */
char        escape = '\033';                     /* Escape character */
int         abort_flag = FALSE;                  /* Abort character detected */
int         fnc_opr;                             /* Function key pushed */
char        *force_cmds = NULL;                  /* Initial commnads */


HANDLE      h_console;                          /* Output handle */

/*
**  Prototypes
*/
int get_kb_character( void );

/*----------------------------------------------------------------------------
** FUNCTION           : set_commands
**
** DESCRIPTION        :
**
**
** INPUTS             : cptr            - Address of commands to execute
**
** RETURNS            : Nothing
**
** PRECONDITION       : 
**
** EXCEPTIONS         :
**
** WARNING            :
**
** SEE ALSO           :
----------------------------------------------------------------------------*/

void set_commands ( char * cptr )
{
    force_cmds = cptr;
}


/*========================================================================
 *
 *  Initialize the screen
 *
 *  Purpose:
 *      This function is called to Initialize the screen
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void init_screen( void )
{
    /*
    **  Save a handle to the console
    */
    h_console = GetStdHandle(STD_OUTPUT_HANDLE);

    /*
    **  Operate within a virtual console area of 24 * 80
    **  Ignore the real console area
    */
    n_lines = 24;                                /* Fix number of lines for export */
    n_cols = 80;                                 /* Number of cols */
}


/*========================================================================
 *
 *  Restore screen to normal
 *
 *  Purpose:
 *      This function is called to Restore screen to normal
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void fix_screen( void )                          /* Restore screen to normal */
{
    flush_out();
}

/*========================================================================
 *
 *  Position the cursor on the screen
 *
 *  Purpose:
 *      This function is called to Position the cursor on the screen
 *
 *  Parameters:
 *      x               col number
 *      y               line number
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void cur( int x, int y )
{
    COORD cursor;

    cursor.Y = y;
    cursor.X = x;
    SetConsoleCursorPosition ( h_console, cursor );
}

/*========================================================================
 *
 *  Position the cursor on the screen
 *
 *  Purpose:
 *      This function is called to save the current cursor location
 *      A single level save - for debug
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/
int save_x,save_y;
void save_cur(void)
{

    CONSOLE_SCREEN_BUFFER_INFO console_info;

    /*
    **  Determine the screen size and the current location of the
    **  cursor within the screen
    */
    GetConsoleScreenBufferInfo( h_console, &console_info );
    save_x = console_info.dwCursorPosition.X;
    save_y = console_info.dwCursorPosition.Y;
}

void restore_cur(void)
{
    cur( save_x, save_y);
}


/*========================================================================
 *
 *  Clears the vdu screen 
 *
 *  Purpose:
 *      This function is called to Clears the vdu screen
 *      From the Microsoft Web Site 
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void clearscreen( void )
{
    COORD coordScreen = { 0, 0 };        /* home for the cursor  */
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    DWORD dwConSize;

    /*
    **   Get the number of character cells in the current buffer.
    */

    if( !GetConsoleScreenBufferInfo( h_console, &csbi ))
        return;
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    /*
    **   Fill the entire screen with blanks.
    */
    if( !FillConsoleOutputCharacter( h_console, (TCHAR) ' ',
                                dwConSize, coordScreen, &cCharsWritten ))
        return;

    /*
    **    Get the current text attribute.
    */
    if( !GetConsoleScreenBufferInfo( h_console, &csbi ))
        return;

    /*
    **  Set the buffer's attributes accordingly.
    */
    if( !FillConsoleOutputAttribute( h_console, csbi.wAttributes,
                                dwConSize, coordScreen, &cCharsWritten ))
        return;

    /*
    **   Put the cursor at its home coordinates.
    */
    SetConsoleCursorPosition( h_console, coordScreen );
}

/*========================================================================
 *
 *  Generate a bell character
 *
 *  Purpose:
 *      This function is called to Generate a bell character
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void beep( void )
{
    putchar( '\007' );
}


/*========================================================================
 *
 *  Flush terminal output
 *
 *  Purpose:
 *      This function is called to Flush terminal output
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void flush_out( void )
{
}


/*========================================================================
 *
 *  Get one character of input
 *
 *  Purpose:
 *      This function is called to Get one character of input
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Ascii code or internal control code which will be greater than
 *      a byte
 *
 *========================================================================*/

int getinp( void )
{

    /*
     * General input routine
     * Will intercept function keys and set flags
     */

    int         c;

    if ( force_cmds && *force_cmds )
    {
        c = *force_cmds++;
    }
    else
    {
        c = get_kb_character();
    }
    if( c & 0xff )
    {
        c = c & 0xff;
        if( c == '\r' )
            c = '\n';
        if( c == ABORT_CHAR || c == ABORT_CHAR_1 )
        {
            abort_flag = TRUE;
            c = ABORT_CHAR;
        }
        return ( c );                            /* Input is ascii char */
    }
    c >>= 8;                                     /* Upper byte */
    if( c >= 59 && c <= 68 )
    {
        fnc_opr = FNC1 + c - 59;
        return ( 0 );
    }
    switch ( c )
    {
    case 71:    return ( HOME_KEY );
    case 72:    return ( UPARROW );
    case 75:    return ( LEFTARROW );
    case 77:    return ( RIGHTARROW );
    case 80:    return ( DOWNARROW );
    case 73:    return ( PAGE_UP );
    case 81:    return ( PAGE_DOWN );
    case 79:    return ( END_KEY );
    case 82:    return ( INSERT_KEY );
    case 83:    return ( DELETE_KEY );
    case 15:    return ( BACKTAB );
    }
    return ( 0 );
}


/*========================================================================
 *
 *  Get a number from the operator
 *
 *  Purpose:
 *      This function is called to get a number from the operator
 *      
 *      This routine will accept numeric data entry from the operator
 *      the routine will limit the operator input to a limited number
 *      of characters. This allowes fixed format input
 *      
 *  Parameters:
 *      max_len         Max field width allowed
 *      final_buf       pointer to the final resting place of the number
 *
 *  Returns:
 *      This routine will return an indication of operator input
 *          0 - No valid entry
 *          1 - data entered and transfered to number.
 *
 *========================================================================*/

bool getnum( int max_len, int *final_buf )
{
    char        n_buf[30];                       /* Convert number here */

    n_buf[0] = '\0';
    if ( *final_buf )
        sprintf( n_buf, "%*.*d", max_len,max_len, *final_buf );
    if( getstring( max_len, n_buf, Digit ) )
    {
        sscanf( n_buf, "%d", final_buf );
        return ( TRUE );
    }
    else
        return ( FALSE );
}

/*========================================================================
 *
 *  Get and edit a string
 *
 *  Purpose:
 *      This function is called to Get and edit a string
 *
 *  Parameters:
 *      len                 Max length of the string
 *      str                 Address of the string
 *      limit               Types of chars allowed
 *
 *  Returns:
 *      Length of the input string
 *
 *========================================================================*/

int getstring( int len, char *str, enum class_enum limit )
{
    char        buf[100];                        /* Internal edit buffer */
    int         i;                               /* Current index into buf */
    int         ii;                              /* Number of characters in buf */
    int         j;                               /* Loooopy variable */
    int         ch;                              /* Current input character */

    ( void ) memset( buf, 0, 100 );              /* Init the buffer */
    ( void ) strcpy( buf, str );                 /* Copy in the original string */
    ii = i = strlen( str );                      /* i is at the end of the string */
    printf( "%s", buf );                         /* Display the current string */

    /*
     * This routine assumes that the cursor is at the end of
     * the string as it is displayed on the screen
     */

    while( !abort_flag )
    {
        ch = getinp();                           /* Get the next character */

        if( ch == '\n' || ch == '\t' || fnc_opr || abort_flag )/* RETURN */
            break;                               /* Finish the edit */

        else if( ch == rubout && i )             /* Users rubout character */
        {
            i--;
            putchar( '\010' );
            for( j = i; j <= ii; j++ )
                buf[j] = buf[j + 1];
            printf( "%s ", &buf[i] );            /* Print remainder of the buffer */
            ii--;                                /* One less in the buffer */
            for( j = i; j <= ii; j++ )
                putchar( '\010' );
        }

        else if( ch == DELETE_KEY && i != ii )   /* Delete char under cursor */
        {
            for( j = i; j <= ii; j++ )
                buf[j] = buf[j + 1];
            printf( "%s ", &buf[i] );
            ii--;
            for( j = i; j <= ii; j++ )
                putchar( '\010' );
        }

        else if( ( ch == '\010' || ch == LEFTARROW ) && i ) /* Back-space */
        {
            i--;
            putchar( '\010' );
        }

        else if( ch == RIGHTARROW && i < ii )    /* forward */
            putchar( buf[i++] );

        else if( ( ii < len ) && ( ( ( limit == Alphanum  || limit == AlphnumUpper) && isprint( ch ) ) || ( ( limit == Digit ) && isascii( ch ) && isdigit( ch ) ) || ( ( limit == Alpha ) && isalpha( ch ) ) ) )    /* Insert the char */
        {
            if ( limit == AlphnumUpper )
                ch = toupper(ch);

            for( j = ii + 1; j > i; j-- )
                buf[j] = buf[j - 1];
            buf[i] = ch;
            ii++;
            printf( "%s", &buf[i++] );  /* Print remainder of the buffer */
            for( j = i; j < ii; j++ )
                putchar( '\010' );
        }
        else
        {
            beep();
        }
    }

    /*
     * Edit complete - transfer the data to the user 
     */

    printf( "%s", &buf[i] );            /* Cursor to end of the buffer */
    if( !abort_flag )
        strcpy( str, buf );             /* Copy buffer to the user */
    else
        ii = 0;
    return ( ii );                               /* Return length of input */
}

/*========================================================================
 *
 *  Get a sex type from the operator
 *
 *  Purpose:
 *      This function is called to Get a sex type from the operator
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      A sex type
 *      The unknown sex type is used to signal no change in state
 *
 *========================================================================*/

sex_type getsex( void )
{
    sex_type    curr = unknown;                  /* current sex type in display */
    char        c;

    while( ( c = getinp() ) != ABORT_CHAR )
    {
        if( c == '\n' || c == '\t' )
        {
            return ( curr );
        }
        if( c == 'M' || c == 'm')
        {
            printf( "Male  \010\010\010\010\010\010" );
            curr = male;
        }
        else if( c == 'F' || c == 'f' )
        {
            printf( "Female\010\010\010\010\010\010" );
            curr = female;
        }
        else
        {
            beep();
        }
    }
    return ( unknown );
}

/*========================================================================
 *
 *  Get a class descriptor
 *
 *  Purpose:
 *      This function is called to Get a class descriptor
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      An integer which is the index into the  config.team_class array
 *
 *========================================================================*/

int getclass( void )
{
    char        cc[3];                           /* Input character */
    int         i, j;                            /* One those loopy things */


    cc[0] = '\0';
    while( ( j = getstring( 2, cc, AlphnumUpper ) ) != 0 )
    {
        /*
        **  Is this a valid class
        */
        if ( (i = lookup_class(cc, NULL)) > 0 )
            return (i);

        /*
        **  Invalid
        **  Rubout and try again
        */
        beep();
        for( i = 0; i < j; i++ )
            putchar( '\010' );
    }
    return ( 0 );
}

/*========================================================================
 *
 *  Get a country descriptor
 *
 *  Purpose:
 *      This function is called to Get a country descriptor
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      An integer which is the index into the config.country_name array.
 *
 *========================================================================*/

int getcountry( void )
{
    char        cc[5];                           /* Input character */
    int         i, j, k;                         /* One those loopy things */

    cc[0] = '\0';
    while( ( j = getstring( 4, cc, Alphanum ) ) != 0 )
    {

        /*
         * Attempt to locate the entered country in the list of defined countries
         */

        for( i = 0; i < MAX_COUNTRY; i++ )
        {
            for( k = 0; k <= j; k++ )
            {
                if( cc[k] == '\000' )
                    return ( ++i );              /* Found it */

                if( toupper( cc[k] ) !=
                    toupper( config.country_name[i].abr[k] ) )
                    break;
            }
        }
        beep();
        for( i = 0; i < j; i++ )
            putchar( '\010' );
    }
    return ( 0 );
}

/*========================================================================
 *
 *  Get menu selector
 *
 *  Purpose:
 *      This function is called to Get menu selector
 *
 *      This function will accept characters until one in
 *      "list" is encountered. This is returned to the user
 *      RETURN is valid if the first character of the list is not a "*"
 *      it will return the first charcater of the list;
 *      ABORT will return a zero
 *
 *  Parameters:
 *      List        A string of valid responses
 *
 *  Returns:
 *      Selected character
 *
 *========================================================================*/

char getfnc( char *list )
{
    char       *copylist;
    char        c;
    char        result = 0;

    copylist = ( *list == '*' ) ? list + 1 : list;
    while( ( c = getinp() ) != ABORT_CHAR )
    {
        c = toupper( c );                        /* Get a character */
        if( strchr( copylist, c ) )
        {
            result = c;
            break;
        }

        if( c == '\n' && *list != '*' )
        {
            result = *list;
            break;
        }

        beep();
    }

    /*
    **  Display the option selected
    **  Not ready for this yet. Looks a bit ugle in a few places
    */
    /*    if ( result )
    **    putchar(result);
    */

    return ( result );
}

/*========================================================================
 *
 *  Prompt for YES / NO
 *
 *  Purpose:
 *      This function is called to Prompt for YES / NO
 *
 *  Parameters:
 *      prompt      Prompt to display to the user
 *
 *  Returns:
 *      TRUE for Yes, FALSE for No
 *
 *========================================================================*/

bool getyes( char *prompt )
{
    char        c;

    printf( "%s ? ", prompt );
    c = getfnc( "*YN" );
    putchar( '\n' );
    return ( c == 'Y' );
}

/*========================================================================
 *
 *  Convert character to upper case
 *
 *  Purpose:
 *      This function is called to convert character to upper case
 *
 *  Parameters:
 *      ch      Character to convert
 *
 *  Returns:
 *      Converted character
 *
 *========================================================================*/

char to_upper( char ch )
{
    if( islower( ch ) )
        return ( ch + 'A' - 'a' );
    return ( ch );
}

/*========================================================================
 *
 *  Convert character to lower case
 *
 *  Purpose:
 *      This function is called to convert character to lower case
 *
 *  Parameters:
 *      ch      Character to convert
 *
 *  Returns:
 *      Converted character
 *
 *========================================================================*/

char to_lower( char ch )
{
    if( isupper( ch ) )
        return ( ch + 'a' - 'A' );
    return ( ch );
}


/*========================================================================
 *
 *  Wait a bit
 *
 *  Purpose:
 *      This function is called to idle and to nothing for a while
 *
 *  Parameters:
 *      t           Time to wait
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void sleep( int t )
{
    Sleep ( t * 1000 );
}


/*========================================================================
 *
 *  Clear to the end of the current display line
 *
 *  Purpose:
 *      Clears to the end of the line
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/
void console_clreol( void )
{

    CONSOLE_SCREEN_BUFFER_INFO console_info;
    DWORD                      rlen;

    int ii;
    int top;


    /*
    **  Determine the screen size and the current location of the
    **  cursor within the screen
    */
    GetConsoleScreenBufferInfo( h_console, &console_info );

    /*
    **  Clear all of it
    */
    top = console_info.dwSize.X - console_info.dwCursorPosition.X;

    for ( ii = 0; ii < top ; ii++ )
    {
        WriteConsole( h_console, " ", 1, &rlen, NULL );
    }
    cur ( console_info.dwCursorPosition.X, console_info.dwCursorPosition.Y );
}

/*========================================================================
 *
 *  printf - Text display routines
 *  putchar - Text display routines
 *
 *
 *  Purpose:
 *      Intercept standard output calls and direct output to the
 *      console.
 *
 *  Parameters: As per standard function definitions
 *      None
 *
 *  Returns:
 *      As per standard function definitions
 *
 *========================================================================*/


int putchar(int cc)
{
    printf( "%c", cc );
    return 1;
}

// void gross_error_message(void)
// {
//     LPVOID lpMsgBuf;
//
//     FormatMessage(
//         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
//         NULL,
//         GetLastError(),
//         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
//         (LPTSTR) &lpMsgBuf,
//         0,
//         NULL
//     );
//
//     // Display the string.
//     MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
//
//     // Free the buffer.
//     LocalFree( lpMsgBuf );
// }

int printf( const char *format, ... )
{
    va_list     ap;
    char        pp[200];
    int         len;
    BOOL        result;
    HANDLE      h_console;

    DWORD       llen;
    DWORD       rlen;


    va_start( ap, format );
    len = vsprintf( pp, format, ap );
    va_end( ap );

    llen = len;
    h_console = GetStdHandle(STD_OUTPUT_HANDLE);
    result = WriteConsole( h_console, pp, llen, &rlen, NULL );
    return ( len );
}

/*========================================================================
 *
 *  Display a prompt character in a highlight
 *
 *  Purpose:
 *      USed to highlight menu entries
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/
void console_prompt( char prompt )
{
    SetConsoleTextAttribute( h_console, FOREGROUND_GREEN );
    putchar( prompt );
    SetConsoleTextAttribute( h_console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
}

/*------------------------------------------------------------------------------
Name:           get_kb_character
Description:    Extract a keyboard character - including cursor and function
                keys.
Parameters:     None
Global Refs:
Returns:        a 16 bit value that encodes ascii character and scan code
Side-effects:
------------------------------------------------------------------------------*/

int get_kb_character( void )
{
    HANDLE          hConsoleInput;
    INPUT_RECORD    Buffer;
    DWORD           NumberOfEventsRead;

    hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);

    /*
    **  Process console events until we get a suitable keystroke event
    */
    FlushFileBuffers( h_console );
    for (;;)
    {
        if (ReadConsoleInput( hConsoleInput, &Buffer, 1, &NumberOfEventsRead ))
        {
            /*
            **  Only want keyboard depression - ignore other events
            */
            if (Buffer.EventType == KEY_EVENT && Buffer.Event.KeyEvent.bKeyDown)
            {
                /*
                **  Ignore several scan codes
                **  CNTRL, ALT, SHIFT, CAPLOCK
                */
                if (Buffer.Event.KeyEvent.wVirtualScanCode == 0x38 ||
                    Buffer.Event.KeyEvent.wVirtualScanCode == 0x1D ||
                    Buffer.Event.KeyEvent.wVirtualScanCode == 0x2A ||
                    Buffer.Event.KeyEvent.wVirtualScanCode == 0x3A)
                {
                    continue;
                }

                return ( (int) (Buffer.Event.KeyEvent.uChar.AsciiChar + (Buffer.Event.KeyEvent.wVirtualScanCode << 8)));
            }
        }
    }

}

/********************************* EOF ***********************************/