/*===========================================================================*\
| QBENCH.C                                                 ver 2.0d, 03-22-89 |
|                                                                             |
| Produces a "screens/second" table for QWIKC Screen Utilities.               |
|                                                                             |
| I'm not trying to support this program, so don't expect it to be            |
| perfect.  It will just give you a good feel for speed.  The time is         |
| adjusted for an average 8 second test for each condition - total of 56      |
| seconds.  For more accurate results, change test_time to 16.  Or for a      |
| quicker but less accurate test, change test_time to 2.                      |
| Be sure to see how fast virtual screens are!                                |
| Also try this out in a multi-tasking environment.                           |
| Test is for 80x25 screens only.                                             |
|                                                                             |
|  Copyright (c) 1988,1989 by James H. LeMay, All rights reserved.            |
|                                                                             |
|  Conversion to Turbo C by Jordan Gallagher / Wisdom Research                |
\*===========================================================================*/

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <process.h>
#include <stdlib.h>

#include "qwikc20.h"
#include "timerd12.h"

enum attrs {
    attr,
    noattr
};

enum procs {
    qwrites,
    qfills,
    qattrs,
    qstores,
    qscrolls
};

#define test_time 8  /* test time in seconds for each case.  8 gives +/- 1% */

int      attrib;
int      count;
unsigned screens;
char     row;
char     col;
char     rows;
char     cols;
float    scrpersec[5][2];
char     strng[81];
int      proc;
int      a;
FILE     *fv;
int      todisk;
int      tovirtual;
char     ch;
vscr_t   oldscr;
unsigned scr1[4000];
unsigned scr2[4000];

char names[5][80] =
{ " qwrite-     ", " qfill-      ", " qattr-      ",
  " qstore-     ", " qscroll-    " };


/******************************| 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, WHITE+BLUE_BG, ' ' );
}


/*******************************| timertest |*******************************\
Clears the screen using the yellow on black attribute.
\***************************************************************************/
void timertest(void)
{
    unsigned char tests=0;

    timer( T_START );
    do {
        for(count=0; count<screens; count++)
            for(row=1; row<=25; row++)
                qwrite( row, 1, YELLOW, strng );
        timer(T_STOP);
        tests++;
    } while( elapsed_time < 1.0 );
    screens = screens*tests*test_time/elapsed_time;
}

/********************************| checktime |******************************\
Checks the timer.
\***************************************************************************/
void check_time(void)
{
    char str2[80];

    if(qsnow)
         screens=8;        /* First guess for screens for 1 second test */
    else screens=80;
    if(tovirtual)
        screens=2;

    strcpy( str2, "TimerTest " );
    for(count=0; count < 3; count++) {         /* copy 3 times */
        strcat( strng, str2 );
    }
    timertest();
}


/*****************************| assemble_strng |****************************\
Sets up a string for displaying based on the functions which are currently
being tested, and whether or not they are writing using attributes.
\***************************************************************************/
void assemble_strng( int proc, int attrib )
{
    strcpy( strng, names[proc] );

    if(qsnow) {
        strcat( strng, " Wait    " );
    } else {
        strcat( strng, " No Wait " );
    }

    if(attrib == SAMEATTR) {
        strcat( strng, " No Attr " );
    } else {
        strcat( strng, " w/ Attr " );
    }

    memset( &strng[31], proc+49, 49 );
    strng[80]=0;                             /* null-terminate */
}


/******************************| time_writing |*****************************\
Times screen writes and fills.
\***************************************************************************/
void time_writing( int proc, int attrib )
{
    int a;

    clearscr();

    if(attrib == SAMEATTR) {
        qattr( 1, 1, crt_rows, crt_cols, LIGHTGRAY );
        a=noattr;
    } else a=attr;

    assemble_strng( proc, attrib );

    switch(proc) {
        case qwrites:
            timer( T_START );

            for(count=1; count <= screens; count++)
                for(row=1; row <= 25; row++)
                    qwrite( row, 1, attrib, strng );

            timer( T_STOP ); break;

        case qfills:
            timer( T_START );

            for(count=1; count <= screens; count++)
                qfill( 1, 1, 25, 80, attrib, 'f' );

            timer( T_STOP ); break;

        case qattrs:
            qfill( 1, 1, 25, 80, attrib, 'a' );
            timer( T_START );

            for(count=1; count <= screens; count++)
                qattr( 1, 1, 25, 80, attrib );

            timer( T_STOP ); break;
    }

    if(elapsed_time != 0.0)
        scrpersec[proc][a] = screens / elapsed_time;
}


/*******************************| time_moving |*****************************\
Times screen block moves.
\***************************************************************************/
void time_moving( int proc, int attrib )
{
    assemble_strng( proc, attrib );

    for(row=1; row <= 25; row++)
        qwrite( row, 1, attrib, strng );

    switch(proc) {
        case qstores:
            timer( T_START );

            for(count=1; count <= screens; count++)
                qstoretomem( 1, 1, 25, 80, scr2 );

            timer( T_STOP ); break;

        case qscrolls:
            timer( T_START );

            for(count=1; count <= screens; count++)
                qscrollup( 1, 1, 25, 80, SAMEATTR );

            timer( T_STOP ); break;
    }

    scrpersec[proc][attr] = screens / elapsed_time;
}


/*******************************| getchoice |*******************************\
Gets input from user.
\***************************************************************************/
char getchoice( char *msg, char answer1, char answer2 )
{
    clearscr();
    qwritec( 12, 1, crt_cols, SAMEATTR, msg );
    gotoeos();
    while((ch=toupper(getch())) != answer1 && ch != answer2 && ch != 13);
    return(ch==answer2);
}


/**********************************| init |*********************************\
Initialize QBENCH.
\***************************************************************************/
void init(void)
{
    qinit();
    check_zenith();
    setmultitask();
    if(inmultask) directvideo=0;
    textattr(WHITE+BLUE_BG);
    clearscr();
}


/******************************| askquestions |*****************************\
\***************************************************************************/
void askquestions(void)
{
    if(qsnow) {
        qsnow=0;

        do {
            do {
                qattr( 1, 1, 10, 80, WHITE+BLUE_BG );
                qwritec( 12, 1, 80, -1, "Do you see "
                         "snow anywhere on the screen? [Y/N]?" );
                gotoeos();
            } while(!kbhit());
            ch=toupper(getch());
        } while( !strchr( "YN", ch ) );

        if(ch == 'Y') {
            qsnow=1;
        } else {
            clearscr();
            qwritec( 10, 1, 80, -1,
            "Congratulations!  You have a card better" );
            qwritec( 11, 1, 80, -1, "than the standard IBM CGA." );
            qwritec( 12, 1, 80, -1,
            "However, to make it faster, you will need" );
            qwritec( 13, 1, 80, -1, "to set qsnow to 0 manually." );
            qwritec( 14, 1, 80, -1, "Please contact us about this." );
            qwritec( 16, 1, 80, -1, "Press any key ...");

            gotorc( 16, 49 );
            if( (ch=getch()) == 0 ) ch=getch();
        }
    }
    tovirtual = getchoice( "Normal or Virtual screen [N/v]? ", 'N', 'V' );
    todisk    = getchoice( "Data to Screen or Disk [S/d]? "  , 'S', 'D' );
    modcursor(cursor_off);
    clearscr();
    oldscr = qscr;
}


/********************************| runtests |*******************************\
\***************************************************************************/
void runtests(void)
{
    if(tovirtual) {
        sprintf( strng, "Please wait %d seconds ...", 7*test_time );
        qwritec( 12, 1, crt_cols, SAMEATTR, strng );
        qscrptr = &scr1;
        qsnow   = 0;
    }
    check_time();
    time_writing( qwrites,  YELLOW+BLUE_BG );
    time_writing( qwrites,  SAMEATTR       );
    time_writing( qfills,   YELLOW+BLUE_BG );
    time_writing( qfills,   SAMEATTR       );
    time_writing( qattrs,   YELLOW+BLUE_BG );
    time_moving(  qstores,  YELLOW+BLUE_BG );
    time_moving(  qscrolls, YELLOW+BLUE_BG );
}


/******************************| printresults |*****************************\
\***************************************************************************/
void printresults(void)
{
    qscr=oldscr;
    clearscr();

    if(todisk)
         fv = fopen( "qbench.dta", "wt" );
    else fv = stdout;

    gotorc( 1, 1 );
    fprintf( fv, "S C R E E N S / S E C O N D\n" );
    fprintf( fv, "             Chng\n" );
    fprintf( fv, "Function     Attr S/sec  Typical for these functions:\n" );
    fprintf( fv, "---------    ---- -----  --------------------------------"
                 "---------------------\n" );

    for(proc=qwrites; proc <= qfills; proc++) {
        for(a=attr; a <= noattr; a++) {
            if(a == attr) {
                fprintf( fv, names[proc] );
            } else {
                fprintf( fv, "             " );
            }

            if(a == attr) {
                fprintf( fv, "Yes " );
            } else {
                fprintf( fv, "No  " );
            }

            fprintf( fv, "%6.1f  ", scrpersec[proc][a] );

            if(a == attr) {
                if(proc == qwrites) {
                    fprintf( fv,
                    "qwrite, qwritec, qwriteeos, qwrite_sub, "
                    "qwriteeos_sub\n" );
                } else
                if(proc == qfills) {
                    fprintf( fv, "qfill, qfillc, qfilleos\n" );
                }
            } else fprintf( fv, "\n" );
        }
    }

    for(proc=qattrs; proc <= qscrolls; proc++) {
        fprintf( fv, "%s", names[proc] );

        if(proc == qattrs) {
            fprintf( fv, "Yes  " );
        } else {
            fprintf( fv, "n/a  " );
        }

        fprintf( fv, "%5.1f  ", scrpersec[proc][attr] );

        switch(proc) {
            case qattrs:
                fprintf( fv, "qattr, qattreos\n" ); break;

            case qstores:
                fprintf( fv,
                "qstoretomem, qstoretoscr, qscrtovscr, qvscrtoscr\n" ); break;

            case qscrolls:
                fprintf( fv, "qscrollup, qscrolldown\n" );
        }
    }

    gotorc( 13, 1 );

    fprintf( fv, "System ID        = 0x%X\n", system_id );
    fprintf( fv, "CPU ID           = %d\n", cpuid );
    fprintf( fv, "Wait-for-retrace = %d\n", qsnow );
    fprintf( fv, "Virtual screen   = %d\n", tovirtual );
    fprintf( fv, "Screens/test     = %d\n", screens );

    fclose( fv );
    gotorc( 24, 1 );
    setcursor( cursor_initial );
}


/**********************************| main |*********************************\
Main block.
\***************************************************************************/
void main(void)
{
    init();

    askquestions();
    runtests();
    printresults();
}

