/***************************************************************************
*   xmstest3.c                                                             *
*   MODULE:  XMSIF                                                         *
*   OS:      DOS                                                           *
*   VERSION: 1.0                                                           *
*   DATE:    12/08/91                                                      *
*                                                                          *
*   Copyright (c) 1991 James W. Birdsall. All Rights Reserved.             *
*                                                                          *
*   Requires xmsif.h, testutil.h, and xmstest.h to compile.                *
*   Compiles under Borland C++ 2.0, Turbo C 2.0, or MSC 6.00A.             *
*                                                                          *
*   Regression test and example for XMSIF. See XMSTEST.C for more detail.  *
*                                                                          *
***************************************************************************/

/*
** system includes <>
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/*
** custom includes ""
*/

#include "xmsif.h"
#include "xmstest.h"

#include "testutil.h"


/*
** local #defines
*/

/*
** misc: copyright strings, version macros, etc.
*/

/*
** typedefs
*/

/*
** global variables
*/

extern int testno;
extern char *gblmsg;


/*
** static globals
*/

/*
** function prototypes
*/

/*
** functions
*/


/***************************************************************************
*   FUNCTION: DO_UMB_TESTS                                                 *
*                                                                          *
*   DESCRIPTION:                                                           *
*                                                                          *
*       Does UMB tests.                                                    *
*                                                                          *
*   ENTRY:                                                                 *
*                                                                          *
*       None.                                                              *
*                                                                          *
*   EXIT:                                                                  *
*                                                                          *
*       Void.                                                              *
*                                                                          *
*   CONSTRAINTS/SIDE EFFECTS:                                              *
*                                                                          *
***************************************************************************/
void do_UMB_tests(void)
{
    unsigned long largest, allsize;
    unsigned long allsize2;
    unsigned long finalsize;
    void far *handle;
    int status;
    int haveUMB = 0;
    int goodallcore = 1;

    gblmsg = "  UMB TESTS";

    /* are there UMBs in this system? */
    TESTHEADER();
    printf("Testing UMBcoreleft() and UMBallcoreleft(), determining whether\n");
    printf("there are UMBs in this system.\n");
    largest = UMBcoreleft();
    weirdcodechk("UMBcoreleft()", 0, (void far *) NULL, 0, 0);
    allsize = UMBallcoreleft();
    if (_XMMerror != 0)
    {
        printf("UMBallcoreleft() returned unexpected code 0x%X\n",
                                                     (unsigned int) _XMMerror);
        printf("Another broken system. *sigh*.\n");
        printf("Values returned by UMBallcoreleft() are junk.\n");
        allsize = ((largest == 0L) ? 0L : (384L * 1024L));
        goodallcore = 0;
    }
    if ((largest == 0L) && (allsize == 0L))
    {
        printf("No UMBs found.\n");
    }
    else
    {
        haveUMB = 1;
    }
    if (allsize < largest)
    {
        printf("UMBallcoreleft() reports total size smaller than size of\n");
        printf("largest UMB (from UMBcoreleft()).\n");
        exit(3);
    }
    /* the theoretical max on UMBs is 384K (1024K - 640K) */
    if (((allsize & 0xF) != 0L) || (allsize > (384L * 1024L)))
    {
        printf("UMBallcoreleft() returned weird value %lu\n", allsize);
        exit(3);
    }
    else if (goodallcore != 0)
    {
        printf("UMBallcoreleft() reports %lu bytes in UMBs.\n", allsize);
    }
    if (((largest & 0xF) != 0L) || (largest > (384L * 1024L)))
    {
        printf("UMBcoreleft() returned weird value %lu\n", largest);
        exit(3);
    }
    else
    {
        printf("UMBcoreleft() reports largest UMB is %lu bytes.\n", largest);
    }
    TESTTAILER();

    /* try allocating a UMB */
    TESTHEADER();
    printf("Testing UMBalloc().\nShould %s.\n",
                                        ((haveUMB == 0) ? "fail" : "succeed"));
    handle = UMBalloc(((haveUMB == 0) ? (largest) : (largest - 1)), &finalsize);
    weirdcodechk("UMBalloc()", 0, (void far *) NULL, 0, 0);
    if (handle == (void far *) NULL)
    {
        if (haveUMB != 0)
        {
            printf("UMBalloc() returned NULL.\n");
            exit(3);
        }
    }
    else
    {
        if (haveUMB == 0)
        {
            printf("UMBalloc() didn't return NULL.\n");
            exit(3);
        }
    }
    if (finalsize != largest)
    {
        printf("Size rounding didn't happen.\n");
        UMBfree(handle);
        exit(3);
    }
    if (goodallcore != 0)
    {
        allsize2 = UMBallcoreleft();
        weirdcodechk("UMBallcoreleft()", 0, (void far *) NULL, 0, 0);
        if (allsize2 != (allsize - finalsize))
        {
            printf("Total dropped weirdly from %lu to %lu\n", allsize,
                                                                     allsize2);
            UMBfree(handle);
            exit(3);
        }
    }
    TESTTAILER();

    /* free it */
    if (haveUMB != 0)
    {
        TESTHEADER();
        printf("Testing UMBfree().\nShould succeed.\n");
        status = UMBfree(handle);
        TRIPLECHECK("UMBfree()", status, 0, (void far *) NULL, 0, 0);
        if (goodallcore != 0)
        {
            allsize2 = UMBallcoreleft();
            weirdcodechk("UMBallcoreleft()", 0, (void far *) NULL, 0, 0);
            if (allsize2 != allsize)
            {
                printf(
                  "Total before UMBalloc(): %lu  Total after UMBfree(): %lu\n",
                  allsize, allsize2);
                exit(3);
            }
        }
    }

    return;
} /* end of do_UMB_tests() */


/***************************************************************************
*   FUNCTION: DO_ICOPY_TESTS                                               *
*                                                                          *
*   DESCRIPTION:                                                           *
*                                                                          *
*       Tests interval copy functions (_XMMicopy() and macros).            *
*                                                                          *
*   ENTRY:                                                                 *
*                                                                          *
*       None.                                                              *
*                                                                          *
*   EXIT:                                                                  *
*                                                                          *
*       Void.                                                              *
*                                                                          *
*   CONSTRAINTS/SIDE EFFECTS:                                              *
*                                                                          *
***************************************************************************/
void do_icopy_tests(void)
{
    int handle;
    unsigned char far *realbuf;
    unsigned char far *guard1, far *guard2, far *guard3;
    unsigned char far *testbuf;
    unsigned char far *testbuf2;
    int status;
    unsigned long start, stop, total;

    /* first, allocate some XMS to test with */
    handle = XMMalloc(MINFREE);
    weirdcodechk("XMMalloc", 0, (void far *) NULL, 0, 0);

    /* next, allocate a conventional memory buffer */
    realbuf = (unsigned char far *) LMALLOC((MINFREE/1024L) + 3);
    if (realbuf == (unsigned char far *) NULL)
    {
        printf("Can't allocate conventional buffer. Aborting.\n");
        XMMfree(handle);
        exit(3);
    }

    /*
    ** Since we can't access EMBs directly, the only way we have of getting
    ** data there is via the copy functions, which we're trying to test. So
    ** the first round of tests will copy data from one half of the
    ** conventional memory to the other, something which we can verify
    ** directly.
    **
    ** Since _XMMcopy is symmetrical, we only need to give one direction
    ** a real workout.
    */
    guard1 = realbuf;
    FMEMSET(guard1, GUARDVAL, 1024);
    testbuf = (unsigned char far *) normptr(guard1 + 1024);
    guard2 = (unsigned char far *) normptr(testbuf + HALFLEN);
    FMEMSET(guard2, GUARDVAL, 1024);
    testbuf2 = (unsigned char far *) normptr(guard2 + 1024);
    guard3 = (unsigned char far *) normptr(testbuf2 + HALFLEN);
    FMEMSET(guard3, GUARDVAL, 1024);
    gblmsg = "  INTERVAL COPY TESTS CONVENTIONAL-CONVENTIONAL";

    /* fill first buffer with incrementing words */
    farincwordfill(testbuf, HALFLEN, 0);
    /* fill second buffer with zero */
    FMEMSET(testbuf2, 0, HALFLEN);

    /* test one-element copy */
    TESTHEADER();
    printf("_XMMicopy(): one-element copy.\nShould succeed.\n");
    status = _XMMicopy(1L, 50, 1, 0, (unsigned long) testbuf, 0,
                                                  (unsigned long) testbuf2, 1);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    GUARDCHECK(handle);
    SRCWORDCHECK(testbuf, HALFLEN);
    CPYWORDCHECK(testbuf2, 50);
    ZEROCHECK((testbuf2 + 50), (HALFLEN - 50));
    TESTTAILER();

    /* restore destination pattern */
    FMEMSET(testbuf2, 0, HALFLEN);

    /* test multi-element copies, even and odd skips */
    TESTHEADER();
    printf("_XMMicopy(): multi-element copies with even and odd skips.\n");
    printf("Should succeed.\n");
    status = _XMMicopy((HALFLEN / 5L), 2, 3, 0, (unsigned long) testbuf, 0,
                                                  (unsigned long) testbuf2, 3);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    status = _XMMicopy((HALFLEN / 5L), 3, 2, 0, (unsigned long)(testbuf + 2), 0,
                                             (unsigned long)(testbuf2 + 2), 2);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    GUARDCHECK(handle);
    SRCWORDCHECK(testbuf, HALFLEN);
    CPYWORDCHECK(testbuf2, HALFLEN);
    TESTTAILER();

    /* restore destination pattern */
    FMEMSET(testbuf2, 0, HALFLEN);

    /* test multi-element copy, zero skip */
    TESTHEADER();
    printf("_XMMicopy(): multi-element copy with zero skip.\n");
    printf("Should succeed.\n");
    status = _XMMicopy((HALFLEN / 1024L), 1024, 0, 0, (unsigned long) testbuf,
                                               0, (unsigned long) testbuf2, 0);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    GUARDCHECK(handle);
    SRCWORDCHECK(testbuf, HALFLEN);
    CPYWORDCHECK(testbuf2, HALFLEN);
    TESTTAILER();


    /*
    ** Now, try various copies to EMB, then copy HALFLEN of EMB back to
    ** testbuf2 for checking.
    */
    gblmsg = "  INTERVAL COPY TESTS CONVENTIONAL-EMB";

    /* restore destination pattern */
    FMEMSET(testbuf2, 0, HALFLEN);
    status = XMMcopyto(HALFLEN, testbuf2, handle, 0L);
    TRIPLECHECK("XMMcopyto()", status, 0, (void far *) realbuf, handle, 0);

    /* test odd and even skips */
    TESTHEADER();
    printf("_XMMicopy(): odd and even skips to zero.\n");
    printf("Should succeed.\n");
    status = _XMMicopy((HALFLEN / 5L), 3, 2, 0, (unsigned long) testbuf,
                                                                handle, 0L, 0);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    status = _XMMicopy((HALFLEN / 5L), 2, 3, 0, (unsigned long)(testbuf + 3),
                                                            handle, 24576L, 0);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    status = _XMMicopy((HALFLEN / 5L), 3, 0, handle, 0L, 0,
                                                  (unsigned long) testbuf2, 2);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    status = _XMMicopy((HALFLEN / 5L), 2, 0, handle, 24576L, 0,
                                             (unsigned long)(testbuf2 + 3), 3);
    TRIPLECHECK("_XMMicopy()", status, 0, (void far *) realbuf, handle, 0);
    GUARDCHECK(handle);
    SRCWORDCHECK(testbuf, HALFLEN);
    CPYWORDCHECK(testbuf2, HALFLEN);
    TESTTAILER();

    /* restore destination pattern */
    FMEMSET(testbuf2, 0, HALFLEN);
    status = XMMcopyto(HALFLEN, testbuf2, handle, 0L);
    TRIPLECHECK("XMMcopyto()", status, 0, (void far *) realbuf, handle, 0);

    /* test zero skip */
    TESTHEADER();
    printf("XMMicopyto() and XMMicopyfrom(): zero skip.\nShould succeed.\n");
    status = XMMicopyto((HALFLEN / 5L), 5, 0, testbuf, handle, 0L);
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    status = XMMicopyfrom((HALFLEN / 16L), 16, 0, handle, 0L, testbuf2);
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    GUARDCHECK(handle);
    SRCWORDCHECK(testbuf, HALFLEN);
    CPYWORDCHECK(testbuf2, HALFLEN);
    TESTTAILER();


    /*
    ** Try some copies with bad offsets, etc., just to make sure _XMMicopy()
    ** is passing along error data from driver OK. _XMMicopy() does no
    ** size checking on its own because it has no idea what the size of
    ** the block is.
    */
    gblmsg = "  INTERVAL COPY TESTS CONVENTIONAL-EMB ERRORS";

    /* try copy with bad starting offset */
    TESTHEADER();
    printf("XMMicopyto(): copying to bad offset.\n");
    printf("Should fail.\n");
    status = XMMicopyto(50L, 2, 2, testbuf, handle, (MINFREE + 1L));
    nofailcheck("XMMicopyto()", status, (void far *) realbuf, handle, 0);
    weirdretchk("XMMicopyto()", status, (void far *) realbuf, handle, 0);
    weirdcodechk("XMMicopyto()", XMM_BADDESTOFF, (void far *) realbuf,handle,0);
    SRCWORDCHECK(testbuf, HALFLEN);
    TESTTAILER();

    /* try copy with bad ending offset */
    TESTHEADER();
    printf("XMMicopyfrom(): copying block that will run off end.\n");
    status = XMMicopyfrom(50L, 2, 2, handle, (MINFREE - 10L), testbuf2);
    nofailcheck("XMMicopyfrom()", status, (void far *) realbuf, handle, 0);
    weirdretchk("XMMicopyfrom()", status, (void far *) realbuf, handle, 0);
    weirdcodechk("XMMicopyfrom()", XMM_BADSRCOFF,(void far *)realbuf,handle,0);
    TESTTAILER();

    /* try copy with source skip too big */
    TESTHEADER();
    printf("_XMMicopy(): source skip too big.\nShould fail.\n");
    status = _XMMicopy(10, 2, 32769U, 0, (unsigned long) testbuf, handle,0L,2);
    nofailcheck("_XMMicopy()", status, (void far *) realbuf, handle, 0);
    weirdretchk("_XMMicopy()", status, (void far *) realbuf, handle, 0);
    weirdcodechk("_XMMicopy()", XMM_SKTOOBIG, (void far *) realbuf, handle, 0);
    SRCWORDCHECK(testbuf, HALFLEN);
    TESTTAILER();

    /* try copy with dest skip too big */
    TESTHEADER();
    printf("_XMMicopy(): dest skip too big.\nShould fail.\n");
    status = _XMMicopy(10, 2, 2, 0, (unsigned long) testbuf, handle,0L,32769U);
    nofailcheck("_XMMicopy()", status, (void far *) realbuf, handle, 0);
    weirdretchk("_XMMicopy()", status, (void far *) realbuf, handle, 0);
    weirdcodechk("_XMMicopy()", XMM_SKTOOBIG, (void far *) realbuf, handle, 0);
    SRCWORDCHECK(testbuf, HALFLEN);
    TESTTAILER();

    /* try copy with element size too big */
    TESTHEADER();
    printf("_XMMicopy(): element size too big.\nShould fail.\n");
    status = _XMMicopy(10, 16385, 2, 0, (unsigned long) testbuf, handle, 0L, 2);
    nofailcheck("_XMMicopy()", status, (void far *) realbuf, handle, 0);
    weirdretchk("_XMMicopy()", status, (void far *) realbuf, handle, 0);
    weirdcodechk("_XMMicopy()", XMM_ELTOOBIG, (void far *) realbuf, handle, 0);
    SRCWORDCHECK(testbuf, HALFLEN);
    TESTTAILER();


    /*
    ** Now, let's do some speed tests (and make sure that we can handle
    ** blocks > 64K). We're going to have to write over the middle
    ** guard block to do it, and move the upper guard block.
    */
    gblmsg = "  INTERVAL COPY TESTS CONVENTIONAL-EMB SPEED";

    guard2 = (unsigned char far *) normptr(testbuf2 + HALFLEN - 1024);
    FMEMSET(guard2, GUARDVAL, 1024);
    LFMEMSET(testbuf, 0, MINFREE);
    status = XMMcopyto(MINFREE, testbuf, handle, 0L);
    TRIPLECHECK("XMMcopyto()", status, 0, (void far *) realbuf, handle, 0);
    lfarincwordfill(testbuf, MINFREE, 0);

    /* first, copy MINFREE bytes by words in two passes */
    TESTHEADER();
    printf("XMMicopyto(): copy %lu bytes by words in two passes.\n", MINFREE);
    printf("Should succeed.\n");
    start = get_tick();
    status = XMMicopyto((MINFREE / 4L), 2, 2, testbuf, handle, 0L);
    stop = get_tick();
    total = stop - start;
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    start = get_tick();
    status = XMMicopyto((MINFREE / 4L), 2, 2, (testbuf + 2), handle, 2L);
    stop = get_tick();
    total += (stop - start);
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    status = XMMcopyfrom(MINFREE, handle, 0L, testbuf);
    TRIPLECHECK("XMMcopyfrom()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    CPYWORDCHECK(testbuf, MINFREE);
    printf("Succeeded. Took %lu ticks.\n", total);
    TESTTAILER();

    /* restore patterns */
    LFMEMSET(testbuf, 0, MINFREE);
    status = XMMcopyto(MINFREE, testbuf, handle, 0L);
    TRIPLECHECK("XMMcopyto()", status, 0, (void far *) realbuf, handle, 0);
    lfarincwordfill(testbuf, MINFREE, 0);

    /* copy MINFREE bytes by fives in two passes */
    TESTHEADER();
    printf("XMMicopyto(): copy %lu bytes by fives in two passes.\n", MINFREE);
    printf("Should succeed.\n");
    start = get_tick();
    status = XMMicopyto((MINFREE / 10L), 5, 5, testbuf, handle, 0L);
    stop = get_tick();
    total = stop - start;
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    start = get_tick();
    status = XMMicopyto((MINFREE / 10L), 5, 5, (testbuf + 5), handle, 5L);
    stop = get_tick();
    total += (stop - start);
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    status = XMMcopyfrom(MINFREE, handle, 0L, testbuf);
    TRIPLECHECK("XMMcopyfrom()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    CPYWORDCHECK(testbuf, MINFREE);
    printf("Succeeded. Took %lu ticks.\n", total);
    TESTTAILER();

    /* restore patterns */
    LFMEMSET(testbuf, 0, MINFREE);
    status = XMMcopyto(MINFREE, testbuf, handle, 0L);
    TRIPLECHECK("XMMcopyto()", status, 0, (void far *) realbuf, handle, 0);
    lfarincwordfill(testbuf, MINFREE, 0);

    /* copy MINFREE bytes individually in two passes */
    TESTHEADER();
    printf("XMMicopyto(): copy %lu bytes individually in two passes.\n",
                                                                      MINFREE);
    printf("Should succeed.\n");
    start = get_tick();
    status = XMMicopyto((MINFREE / 2L), 1, 1, testbuf, handle, 0L);
    stop = get_tick();
    total = stop - start;
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    start = get_tick();
    status = XMMicopyto((MINFREE / 2L), 1, 1, (testbuf + 1), handle, 1L);
    stop = get_tick();
    total += (stop - start);
    TRIPLECHECK("XMMicopyto()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    status = XMMcopyfrom(MINFREE, handle, 0L, testbuf);
    TRIPLECHECK("XMMcopyfrom()", status, 0, (void far *) realbuf, handle, 0);
    if ((farmemcheck(guard1, 1024, GUARDVAL) != 0) ||
        (farmemcheck(guard2, 1024, GUARDVAL) != 0))
    {
        printf("Copy corrupted guard buffers.\n");
        XMMfree(handle);
        LFREE(realbuf);
        exit(3);
    }
    CPYWORDCHECK(testbuf, MINFREE);
    printf("Succeeded. Took %lu ticks.\n", total);
    TESTTAILER();


    /*
    ** Clean up.
    */
    LFREE(realbuf);
    test_XMMfree(handle);

    return;
} /* end of do_icopy_tests() */

