/*===========================================================================*\
| QINITEST.C                                              ver 2.0d, 03-22-89  |
|                                                                             |
| Tests your system configuration                                             |
|                                                                             |
|  Copyright (c) 1988,1989 by James H. LeMay, All rights reserved.            |
|                                                                             |
|  Conversion to Turbo C by Jordan Gallagher / Wisdom Research                |
\*===========================================================================*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <dos.h>

#include "qwikc20.h"

/* un-comment the line below to include IBM's submodel ID detection */
/* #define ADD_SUBMODEL */

char newmode, oldmode;
char strng[80];
char ch;
int cursor_delay=1500;

/******************************| check_zenith |*****************************\
Since Zenith doesn't have snow on any CGAs, turn off snow checking.
\***************************************************************************/
void check_zenith(void)
{
    char far *zds_rom=(char far *) 0xF000800CL;

    if(qsnow && strcmp( (char *) zds_rom, "ZDS CORP" ) == 0) {
        qsnow=0;
        cardsnow=0;
    }
}


/********************************| clearscr |*******************************\
Clears the screen using the yellow on black attribute.
\***************************************************************************/
void clearscr(void)
{
    qfill( 1, 1, crt_rows, crt_cols, YELLOW+BLUE_BG, ' ' );
}


/*********************************| init |***********************************\
Initializes by checking for Zenith and clearing the screen.
\****************************************************************************/
void init(void)
{
    qreinit();

    check_zenith();
    setmultitask();
    if(inmultask) directvideo=0;

    textattr(YELLOW+BLUE_BG);
    clearscr();
}


/********************************| btoa |************************************\
Converts a long to a string.  The target string contains the long in
binary form, i.e. "10100101101101010010010110110101".
The parameter bitcnt specifies the number of bits to be processed.
The return value is a pointer to the target string.
\****************************************************************************/
char *btoa( long val, char bitcnt, char *string )
{
    char bit;

    for(bit=0; bit < bitcnt; bit++) {
        string[bit] = ((val >> bit) & 1) + 48;
    }
    string[bit]=0;

    return(string);
}


/********************************| htoa |************************************\
Converts a long to a string.  The target string contains the long in
hexadecimal form, i.e. "21CF89A5".
The parameter hcnt specifies the amount of characters the target
string should contain.
The return value is a pointer to the target string.
\****************************************************************************/
char *htoa( long val, char hcnt, char *string )
{
    if(hcnt > 4)
        sprintf( string, "0x%*lX", hcnt, val );
    else
    if(hcnt > 2)
        sprintf( string, "0x%0*X", hcnt, (int) val );
    else
    if(hcnt <= 2)
        sprintf( string, "0x%0*hX", hcnt, (unsigned char) val );

    return(string);
}


/*********************************| stryn |**********************************\
Places the string "YES" or "NO" in the str parameter based on whether
the specified int is 1 or 0.
\****************************************************************************/
char *stryn( int val, char *str )
{
    return(strcpy( str, val ? "YES" : "NO" ));
}


/******************************| display_dev |*******************************\
Sets the global variable "strng" based on the specified display device's
number.
\****************************************************************************/
void display_dev( char dd )
{
    switch(dd) {
        case 0x00: strcpy( strng, "No display" );                  break;
        case 0x01: strcpy( strng, "MDA with 5151 monochrome" );    break;
        case 0x02: strcpy( strng, "CGA with 5153/4 color" );       break;
        case 0x04: strcpy( strng, "EGA with 5153/4 color" );       break;
        case 0x05: strcpy( strng, "EGA with 5151 monochrome" );    break;
        case 0x06: strcpy( strng, "PGC with 5175 color" );         break;
        case 0x07: strcpy( strng, "VGA with analog monochrome" );  break;
        case 0x08: strcpy( strng, "VGA with analog color" );       break;
        case 0x0B: strcpy( strng, "MCGA with analog monochrome" ); break;
        case 0x0C: strcpy( strng, "MCGA with analog color" );      break;
        default:   strcpy( strng, "Reserved" );
    }
}


/*****************************| do_setcursor |*******************************\
Calls setcursor with the cursor parameter, and displays the specified
message along with a hexadecimal version of the cursor word.
\****************************************************************************/
void do_setcursor( char *msg, int cursor )
{
    char msg1[80],msg2[80];

    strcpy( msg1, msg );
    htoa( cursor, 4, msg2 );

    setcursor( cursor );
    qwriteeos( SAMEATTR, strcat( msg1, msg2 ) );
    gotoeos();
    delay( cursor_delay );
    eosln();
}


/*****************************| do_modcursor |*******************************\
Calls modcursor with the cursor parameter, and displays the specified
message along with a hexadecimal version of the cursor's word after
being set by modcursor.
\****************************************************************************/
void do_modcursor( char *msg, int cursor )
{
    char msg1[30],msg2[10],msg3[10];

    modcursor( cursor );
    strcpy( msg1, msg );
    htoa( cursor, 4, msg2 );
    htoa( getcursor(), 4, msg3 );
    strcat( msg1, msg2 );
    strcat( msg1, " " );
    strcat( msg1, msg3 );

    qwriteeos( SAMEATTR, msg1 );
    gotoeos();
    delay( cursor_delay );
    eosln();
}


/*******************************| waitkey |**********************************\
Waits for a keypress, eliminating extra key-ahead if an extended key
is pressed, generating an escape sequence.
\****************************************************************************/
void waitkey(void)
{
    qwrite( crt_rows, 1, SAMEATTR, "Press any key..." );
    gotoeos();

    do ch=getch(); while(kbhit());
}


/*********************************| main |***********************************\
The main block.
\****************************************************************************/
main()
{
    char s[80];

    qinit();

    init();
    oldmode=qvideo_mode;

    qwrite( 1, 1, SAMEATTR, "Which text mode (0,1,2,3,7) ? " );
    gotoeos();

    while( !strchr( "01237", (ch=getch()) ) );
    newmode=ch-'0';

    if(newmode != oldmode) {
        textmode( newmode );
        qreinit();
    }

    init();

    switch( cpuid ) {
        case cpu8086:  strcpy( strng, "Intel 8086/88"   ); break;
        case cpu80186: strcpy( strng, "Intel 80186/188" ); break;
        case cpu80286: strcpy( strng, "Intel 80286"     ); break;
        case cpu80386: strcpy( strng, "Intel 80386"     ); break;
    }

    qwrite( 1, 1, SAMEATTR, "CPU ident         = " );
    qwriteeos( SAMEATTR, strng );

#ifdef ADD_SUBMODEL
    get_submodel_id();           /* Check docs before using this function. */
#endif

    switch(system_id) {
        case 0xFF: strcpy( strng, "IBM PC"    ); break;
        case 0xFE: strcpy( strng, "IBM PC XT" ); break;
        case 0xFD: strcpy( strng, "IBM PCjr"  ); break;
        case 0xFC:
            switch(submodel_id) {
                case 0:  strcpy( strng, "IBM PC AT (6 MHz)" ); break;
                case 1:  strcpy( strng, "IBM PC AT (8 MHz)" ); break;
                case 2:  strcpy( strng, "IBM PC XT (286)"   ); break;
                case 4:  strcpy( strng, "IBM PS/2 Model 50" ); break;
                case 5:  strcpy( strng, "IBM PS/2 Model 60" ); break;
                default: strcpy( strng, "IBM PS/2 VGA type" ); break;
            } break;
        case 0xFB: strcpy( strng, "IBM PC XT (256/640)" ); break;
        case 0xFA:
            switch(submodel_id) {
                case 0:  strcpy( strng, "IBM PS/2 Model 30" );
                case 1:  strcpy( strng, "IBM PS/2 Model 25" );
                default: strcpy( strng, "IBM PS/2 MCGA type" );
            } break;
        case 0xF9: strcpy( strng, "IBM PC convertible" ); break;
        case 0xF8:
            switch(submodel_id) {
                case 0:  strcpy( strng, "IBM PS/2 Model 80 (16 MHz)" ); break;
                case 1:  strcpy( strng, "IBM PS/2 Model 80 (20 MHz)" ); break;
                case 9:  strcpy( strng, "IBM PS/2 Model 70 (16 MHz)" ); break;
                default: strcpy( strng, "IBM PS/2 Model 70/80 type"  ); break;
            } break;
        default: strcpy( strng, "Unknown, not an IBM" ); break;
    }

    qwrite( 2, 1, SAMEATTR, "System ID         = " );
    qwriteeos( SAMEATTR, htoa( system_id, 2, s ) );

    qwrite( 3, 1, SAMEATTR, "Submodel ID       = " );

#ifdef ADD_SUBMODEL
    qwriteeos( SAMEATTR, itoa( submodel_id, s, 10 ) );
#else
    qwriteeos( SAMEATTR, "??" );
    strcpy( strng, "(detection disabled - see QINITEST.C)" );
#endif

    qwrite( 4, 3,  SAMEATTR, strng );
    qwrite( 5, 1,  SAMEATTR, "Have PS/2 video   = " );
    qwriteeos(     SAMEATTR, stryn( have_ps2, s ) );
    qwrite( 6, 1,  SAMEATTR, "IBM 3270 PC       = " );
    qwriteeos(     SAMEATTR, stryn( have_3270, s ) );
    qwrite( 7, 1,  SAMEATTR, "Prior video mode  = " );
    qwriteeos(     SAMEATTR, itoa( oldmode, s, 10 ) );
    qwrite( 8, 1,  SAMEATTR, "Video mode now    = " );
    qwriteeos(     SAMEATTR, itoa( qvideo_mode, s, 10 ) );
    qwrite( 9, 1,  SAMEATTR, "Wait-for-retrace  = " );
    qwriteeos(     SAMEATTR, stryn( qsnow, s ) );
    qwrite( 10, 1, SAMEATTR, "Max page #        = " );
    qwriteeos(     SAMEATTR, itoa( maxpage, s, 10 ) );

    if(have_3270) {
        qwrite( 11, 1, SAMEATTR, "Disp dev 3270     = " );
        qwriteeos( SAMEATTR, htoa( active_disp_dev_3270, 2, s ) );

        switch( active_disp_dev_3270 ) {
          case 0: strcpy(strng, "5151 or 5272 display and adapter");     break;
          case 1: strcpy(strng, "3295 display and adapter");             break;
          case 2: strcpy(strng, "5151 or 5272, adapter, XGA graphics");  break;
          case 3: strcpy(strng, "5279 display, 3270 PC G adapter");      break;
          case 4: strcpy(strng, "5379 C01 display, 3270 PC GX adapter"); break;
          case 5: strcpy(strng, "5379 M01 display, 3270 PC GX adapter"); break;
          case 0xFF: strcpy(strng, "Unknown, not a 3270 PC");            break;
          default: strcpy( strng, "Reserved" );                          break;
        }

        qwrite( 12, 3, SAMEATTR, strng );
    } else {
        display_dev( active_disp_dev );
        qwrite( 11, 1, SAMEATTR, "Active Disp Dev   = " );
        qwriteeos(     SAMEATTR, itoa( active_disp_dev, s, 10 ) );
        qwrite( 12, 3, SAMEATTR, strng );

        if(system_id == 0xF9) {       /* PC convertible */
            qwrite( 13, 1, SAMEATTR, "Alt Disp Dev PC Conv = " );
            qwriteeos(     SAMEATTR, itoa( alt_disp_dev_pcc, s, 10 ) );
        } else {
            display_dev( alt_disp_dev );
            qwrite( 13, 1, SAMEATTR, "Alt Disp Dev      = " );
            qwriteeos(     SAMEATTR, itoa( alt_disp_dev, s, 10 ) );
            qwrite( 14, 3, SAMEATTR, strng );
        }

        qwrite( 15, 1, SAMEATTR, "Hercules model    = " );
        qwriteeos(     SAMEATTR, itoa( herc_model, s, 10 ) );

        switch(herc_model) {
            case 0: strcpy( strng, "No Hercules card" );             break;
            case 1: strcpy( strng, "Hercules Graphics Card" );       break;
            case 2: strcpy( strng, "Hercules Graphics Card Plus" );  break;
            case 3: strcpy( strng, "Hercules InColor Card" );        break;
        }

        qwrite( 16, 3, SAMEATTR, strng );
    }

    qwrite( 17, 1, SAMEATTR, "CRT rows          = " );
    qwriteeos(     SAMEATTR, itoa( crt_rows, s, 10 ) );
    qwrite( 18, 1, SAMEATTR, "CRT columns       = " );
    qwriteeos(     SAMEATTR, itoa( crt_cols, s, 10 ) );
    qwrite( 19, 1, SAMEATTR, "Cursor start      = " );
    qwriteeos(     SAMEATTR, itoa( (char) cursor_initial, s, 16 ) );
    qwrite( 20, 1, SAMEATTR, "Cursor end        = " );
    qwriteeos(     SAMEATTR, itoa( (char) cursor_initial >> 4, s, 16 ) );

    if(active_disp_dev >= ega_color && active_disp_dev <= mcga_color) {
        qwrite( 21, 1, SAMEATTR, "EGA rows          = " );
        qwriteeos(     SAMEATTR, itoa( egarows, s, 10 ) );
        qwrite( 22, 1, SAMEATTR, "EGA FontSize      = " );
        qwriteeos(     SAMEATTR, itoa( egafontsize, s, 10 ) );
        qwrite( 23, 1, SAMEATTR, "EGA Info          = " );
        qwriteeos(     SAMEATTR, btoa( egainfo, 8, s ) );
        qwrite( 24, 1, SAMEATTR, "EGA Switches      = " );
        qwriteeos(     SAMEATTR, btoa( ega_switches, 8, s ) );
    }

    waitkey();
    clrscr();

    qwritec( 1, 1, crt_cols, SAMEATTR, "Cursor Modes Test:" );
    qwrite( 3, 1, SAMEATTR, "SET              MODE" );
    qwrite( 4, 1, SAMEATTR, "-------------   ------" );
    eosln();

    do_setcursor( "Initial       = ", cursor_initial );
    do_setcursor( "Underline     = ", cursor_underline );
    do_setcursor( "Half-block    = ", cursor_halfblock );
    do_setcursor( "Block         = ", cursor_block );
    eosln();

    qwriteeos( SAMEATTR, "MODIFY           MASK   MODE" );
    qwrite( eosr()+1, 1, SAMEATTR, "-------------   ------ ------" );
    eosln();

    do_modcursor( "Off           = ", cursor_off );
    do_modcursor( "On            = ", cursor_on );
    do_modcursor( "Erratic Blink = ", cursor_blink );

    setcursor( cursor_initial );
    waitkey();
    textmode( oldmode );

    return;
}

