Category : C Source Code
Archive   : AXMSLIB.ZIP
Filename : XMSLIB.C
Output of file : XMSLIB.C contained in archive : AXMSLIB.ZIP
* ---------------------------------------------------------------
*
* $Revision: 1.0 $
* $Date: 28 Feb 1992 8:54:56 $
* $Log: F:/XMSLIB/VCS/XMSLIB.C_V $
*
* Rev 1.0 28 Feb 1992 8:54:56
* Initial revision.
*
* ---------------------------------------------------------------
*/
/* ------------------------ Pragmas -------------------------- */
/* ---------------------- Include files ----------------------- */
#include
#include
#if defined ( _M_DEBUG )
#include
#endif
#include
#include "xmslib.h"
/* -------------------- Local definitions --------------------- */
#define _CPYR_ " Copyright (C) 1992 M.G.A.Wilson"
#if defined ( M_I86SM ) // Microsoft, small
#define APICALL call far ptr [mpXMSAPI]
#define EAPICALL call far ptr es:[mpXMSAPI]
#elif (defined ( __SMALL__ )) // Borland, small
#define APICALL call dword ptr mpXMSAPI
#define EAPICALL call dword ptr es:mpXMSAPI
#elif (defined ( __LARGE__ ) || defined ( M_I86LM )) // Large
#define APICALL call [mpXMSAPI]
#define EAPICALL call es:[mpXMSAPI]
#else
#error Unsupported compiler or memory model.
#endif
#define H_640K 0 // XMS move handle for 640K conventional memory
typedef struct tagXMSMOVE // Extended Memory Move Structure
{ // ------------------------------
DWORD ulLength; // Number of bytes to transfer
WORD uSrcHdl; // Handle to source block
DWORD ulSrcOfs; // Offset into source block
WORD uDestHdl; // Handle to destination block
DWORD ulDestOfs; // Offset into destination block
}
XMSMOVE_T; // Handle(s) == H_640K for conventional memory
typedef struct tagXMSCTRL // Extended Memory Control structure
{ // ---------------------------------
WORD uHandle; // Handle to the actual XMS block
WORD uHiWater; // `High water' mark: offset of 1st free byte
WORD uNumK; // Number of Kbytes in the block (1..64)
BOOLEAN fCompacted; // TRUE if the free blocks have been compacted
}
XMSCTRL_T;
typedef struct tagXMSBLOCKHEADER // Extended Memory Allocation Block Header
{ // ---------------------------------------
WORD uLength; // Number of data bytes in the block
WORD uData; // Data, or number of free data bytes, if
} //
XMSBLOCKHEADER_T;
/* ------------------- Function prototypes -------------------- */
/* ------------------------- Globals -------------------------- */
static const char mszIdent[] = { "@(#)XMSLIB v1.00" _CPYR_ };
static DWORD mpXMSAPI; // XMS API entry point
static WORD muXMSerrCode; // Error code returned by API call
static WORD muCtrlBlks = 0, // Number of XMS control blocks
muCurrCtrlBlk = 0; // Current XMS control block
static XMSCTRL_T * mpXMCtrl = NULL; // Pointer to (array of) ctrl blocks
/* ------------------------------------------------------------
The control structure maintained in conventional RAM looks like this:
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
Hi³ Control block N ³ Each control block contains a handle to an
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ XMS memory block (16-bit word) and the current
. . . `high water' mark in the control block, that
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ is, the offset of the first byte where
³ Control block 1 ³ allocated data can be placed.
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
Lo³ Control block 0 ³ The number of blocks is fixed by XMSopen()
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The structure of a partially-used block in XMS memory looks like this:
ÚÄÂÄÄÄÄÂÄÂÄÄÄÄÄÄÄÄÂÄÂÄÄÂÄÂÄÄÄÄÄÄÄÂÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³a³XXXX³b³XXXXXXXX³0³cX³d³XXXXXXX³e³XXXXXXXXXXXX³0³00000000000000000000³
ÀÄÁÄÄÄÄÁÄÁÄÄÄÄÄÄÄÄÁÄÁÄÄÁÄÁÄÄÄÄÄÄÄÁÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Here, letters `a',`b' etc. represent the start of allocation units. Each
contains a 16-bit word holding the LENGTH OF DATA FOLLOWING THE WORD. The
total length of the unit is therefore (length)+2 bytes. If a length is
marked as 0, then the block is free and can be (re)used for storage.
If it has never been used, then the first word of the data will also be 0,
and all space up to the end of the XMS block will thterefore be available.
If the block has been previously used and then freed, the length of the
(old) block will be stored in the first word of the data. A check for a
fit of the newly-allocated block can then be made (which may generate a
new, smaller freed block if the fit is not exact).
------------------------------------------------------------ */
// X M S g e t A P I a d d r e s s
// -------------------------------
// Locates the call gate to the XMS application programming interface
// and stores it in the global
//
static void _near XMSgetAPIaddress (void)
{
_asm {
mov ax,4310h
int 2Fh
mov word ptr [mpXMSAPI],bx
mov word ptr [mpXMSAPI + 2],es
}
}
// X M S g e t F r e e M e m
// -------------------------
//
static WORD _near XMSgetFreeMem (WORD * puLargestBlk)
{
WORD uTotal, uLargest;
_asm {
mov ah,8
APICALL
mov [muXMSerrCode],bx
mov uLargest,ax
mov uTotal,dx
}
*puLargestBlk = uLargest;
return uTotal;
}
// X M S a l l o c B l o c k
// -------------------------
// Allocate a block of
//
// Returns:
// Handle to the block, or 0 if none could be allocated
//
static WORD _near XMSallocBlock (WORD uKbytes)
{
WORD hXM = 0; // The handle
_asm {
mov ah,9
mov dx,uKbytes
APICALL
mov [muXMSerrCode],bx
or ax,ax
jz AllocOver
mov hXM,dx
}
AllocOver:
return hXM;
}
// X M S f r e e B l o c k
// -----------------------
// Free a block of XMS memory accessed through handle
//
// Returns:
// 1 if successfully freed, 0 if not
//
static int _near XMSfreeBlock (WORD hXM)
{
int fSuccess;
_asm {
mov ah,0Ah
mov dx,hXM
APICALL
mov [muXMSerrCode],bx
mov fSuccess,ax
}
return fSuccess;
}
// X M S m o v e
// -------------
// Transfer data to or from XMS memory
//
// Argument:
//
//
// Returns:
// 1 for success, 0 on error
//
static int _near XMSmove (XMSMOVE_T _far * pXMSmv)
{
int fSuccess;
unsigned uSegment = FP_SEG(pXMSmv),
uOffset = FP_OFF(pXMSmv);
_asm {
mov ax,ds
mov es,ax
push ds
push si
mov si,uOffset
mov ax,uSegment
mov ds,ax
mov ah,0Bh
EAPICALL
mov es:[muXMSerrCode],bx
pop si
pop ds
mov fSuccess,ax
}
return fSuccess;
}
// X M S a l l o c W r i t e
// -------------------------
// Write control information into XMS memory to mark an allocated block
//
// Arguments:
//
//
//
//
// Returns:
// Handle to memory, or XMSHNULL on error
//
static XMSHANDLE _near XMSallocWrite (WORD hXM, WORD uOfs, WORD uBytes)
{
XMSBLOCKHEADER_T XMShdr;
XMSMOVE_T XMSmv;
XMSHANDLE xhXM = XMSHNULL;
XMShdr.uLength = uBytes;
XMShdr.uData = 0;
XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
XMSmv.uSrcHdl = H_640K;
XMSmv.ulSrcOfs = (DWORD)((char _far *)&XMShdr);
XMSmv.uDestHdl = hXM;
XMSmv.ulDestOfs = (DWORD)uOfs;
if (XMSmove(&XMSmv))
{
xhXM = ((DWORD)hXM << 16);
xhXM += uOfs;
}
return xhXM;
}
// C o a l e s c e F r e e U n i t s
// ---------------------------------
// Join contiguous freed blocks in an allocation unit into a single free block
//
// Argument:
//
//
static void _near _fastcall CoalesceFreeUnits (XMSCTRL_T * pXMCtrl)
{
if (!pXMCtrl->fCompacted)
{
XMSBLOCKHEADER_T XMShdrThis,
XMShdrNext;
XMSMOVE_T XMSmv;
WORD uOfs = 0,
uRefOfs;
#if (defined ( _M_DEBUG ) && defined ( _M_VERBOSE ))
printf("\n--> COALESCING BLOCK WITH HANDLE %04x\n", pXMCtrl->uHandle);
#endif
XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
while (uOfs < pXMCtrl->uHiWater)
{
WORD uFreeLen = 0;
BOOLEAN fBlockEnd = FALSE;
XMSmv.uSrcHdl = pXMCtrl->uHandle;
XMSmv.uDestHdl = H_640K;
XMSmv.ulSrcOfs = uRefOfs = uOfs;
XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdrThis);
if (!XMSmove(&XMSmv))
return;
XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdrNext);
if (XMShdrThis.uLength == 0)
{
WORD uExtraLen = 0;
// This block is free: iterate through the following blocks,
// accumulating the total free length...
do
{
if (XMShdrThis.uData == 0) // Hit end of chain
{
uFreeLen = 0; // Original now marks end of chain
fBlockEnd = TRUE;
break;
}
uFreeLen += (XMShdrThis.uData + uExtraLen);
uOfs += (XMShdrThis.uData + sizeof(WORD));
if (uOfs >= pXMCtrl->uHiWater)
{
fBlockEnd = TRUE;
break;
}
XMSmv.ulSrcOfs = uOfs;
if (!XMSmove(&XMSmv)) // Read next header
return;
XMShdrThis = XMShdrNext;
uExtraLen = sizeof(WORD); // Count 2 byte length on all but 1st block
}
while (XMShdrThis.uLength == 0);
// Now update the *original* free block with the coalesced length
XMShdrNext.uLength = 0;
if (fBlockEnd == TRUE && uRefOfs == 0)
// Special case -- all blocks empty
XMShdrNext.uData = 0;
else
XMShdrNext.uData = uFreeLen;
XMSmv.uSrcHdl = H_640K;
XMSmv.ulSrcOfs = (DWORD)((char _far *)&XMShdrNext);
XMSmv.uDestHdl = pXMCtrl->uHandle;
XMSmv.ulDestOfs = uRefOfs;
XMSmove(&XMSmv);
if (fBlockEnd == TRUE)
{
// Update high water mark to new end of block
pXMCtrl->uHiWater = uRefOfs;
break;
}
}
else
uOfs += (XMShdrThis.uLength + sizeof(WORD));
}
pXMCtrl->fCompacted = TRUE;
}
}
// X M S a l l o c P l a n B
// -------------------------
// Allocator called when we've hit the high water mark in the last XMS block
//
// Argument:
//
//
// Returns:
// Handle to memory, or XMSHNULL on error
//
static XMSHANDLE _near XMSallocPlanB (WORD uBytes)
{
XMSCTRL_T * pXMCtrl = mpXMCtrl;
for (muCurrCtrlBlk = 0;
muCurrCtrlBlk < muCtrlBlks; // For each XMS block...
muCurrCtrlBlk++, pXMCtrl++)
{
WORD uOfs = 0; // Start at the bottom...
XMSBLOCKHEADER_T XMShdr;
XMSMOVE_T XMSmv;
CoalesceFreeUnits(pXMCtrl);
XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
XMSmv.uSrcHdl = pXMCtrl->uHandle;
XMSmv.uDestHdl = H_640K;
XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdr);
do
{
XMSmv.ulSrcOfs = uOfs;
XMSmove(&XMSmv);
if (XMShdr.uLength == 0)
{
// This block is reusable
if (XMShdr.uData >= uBytes + sizeof(WORD) + sizeof(WORD))
{
#if (defined ( _M_DEBUG ) && defined ( _M_VERBOSE ))
printf("Reusing block of %04x bytes at %04x : New blocks %04x and %04x\n",
XMShdr.uData, uOfs, uBytes, XMShdr.uData - uBytes - sizeof(WORD));
#endif
// Got space in middle of block -- write a new free block beyond it
XMShdr.uData -= (uBytes + sizeof(WORD));
XMSmv.uDestHdl = XMSmv.uSrcHdl;
XMSmv.uSrcHdl = H_640K;
XMSmv.ulSrcOfs = XMSmv.ulDestOfs;
XMSmv.ulDestOfs = uOfs + uBytes + sizeof(WORD);
XMSmove(&XMSmv);
return XMSallocWrite(pXMCtrl->uHandle, uOfs, uBytes);
}
else
{
// Not big enough for allocation
if (XMShdr.uData == 0)
{
// Block has never been used; work out length
WORD uLen = 0xFFFF - uOfs;
if (uLen < uBytes + sizeof(WORD) - 1)
// No space in this block; try next
break;
// Got space at end of block
pXMCtrl->uHiWater = uOfs + uBytes + sizeof(WORD);
return XMSallocWrite(XMSmv.uSrcHdl, uOfs, uBytes);
}
// Skip to next
uOfs += XMShdr.uData;
}
}
else
// This block ain't reusable: skip to next
uOfs += XMShdr.uLength;
uOfs += sizeof(WORD);
}
while (uOfs < pXMCtrl->uHiWater);
}
muCurrCtrlBlk = 0;
return XMSHNULL;
}
// -----------------------------------------------------------------------
// ----- E x t e r n a l l y - v i s i b l e f u n c t i o n s -----
// -----------------------------------------------------------------------
// X M S i n s t a l l e d
// -----------------------
// Returns:
// 1 if XMS memory is installed, else 0
//
int XMSinstalled (void)
{
int fInstalled;
_asm {
mov ax,4300h
int 2Fh
and ax,0080h
mov cl,7
shr al,cl
mov fInstalled,ax
}
return fInstalled;
}
// X M S g e t V e r s i o n
// -------------------------
// Gets the version of XMS memory driver (e.g. HIMEM.SYS) in use
//
// Returns:
// BCD coded number (e.g. v3.21 -> 0x0321), or 0 if not installed or
// the XMS library's XMSopen() function has not been called.
//
WORD XMSgetVersion (void)
{
WORD uVersion = 0;
if (XMSinstalled() && mpXMSAPI != 0L)
{
_asm {
mov ah,0
APICALL
mov uVersion,bx
}
}
return uVersion;
}
// X M S o p e n
// -------------
// `Open communications' with extended memory
//
// Argument:
//
//
// Returns:
// 1 for success
// 0 for failure
//
// Notes:
// A value of 0 for
// The call will fail if the entire amount requested can not be obtained.
// At least 64K extended memory must be available as a contiguous block.
//
int XMSopen (WORD uKbytes)
{
if (muCtrlBlks == 0)
{
WORD uKlargestAvail,
uLastK;
XMSgetAPIaddress();
XMSgetFreeMem(&uKlargestAvail);
if (uKbytes == 0)
{
if (uKlargestAvail >= 64)
muCtrlBlks = (uKlargestAvail / 64);
}
else if (uKlargestAvail >= uKbytes)
muCtrlBlks = (uKbytes / 64) + 1;
if ((uLastK = (uKbytes % 64)) == 0)
uLastK = 64;
if (muCtrlBlks > 0)
{
muCurrCtrlBlk = 0;
if ((mpXMCtrl = (XMSCTRL_T *)calloc(muCtrlBlks, sizeof(XMSCTRL_T)))
!= NULL)
{
// XMS control blocks are pre-filled with zeroes. Now do the
// actual carving up of the extended memory...
XMSCTRL_T * pXMCtrl = mpXMCtrl;
WORD uCount;
for (uCount = 0; uCount < muCtrlBlks; uCount++)
{
WORD uNumK = (uCount == muCtrlBlks - 1 ? uLastK : 64);
WORD uHandle = XMSallocBlock(uNumK);
if (uHandle > 0)
{
pXMCtrl->uHandle = uHandle;
pXMCtrl->uNumK = uNumK;
pXMCtrl->fCompacted = TRUE;
pXMCtrl++;
}
else
{
muCtrlBlks = uCount;
break;
}
}
}
else
muCtrlBlks = 0;
}
return(muCtrlBlks > 0);
}
// XMSopen() already called with no intervening XMSclose()
return 0;
}
// X M S c l o s e
// ---------------
// `Close communications' with XMS memory
//
// Returns:
// 1 for success
// 0 for failure
//
// Notes:
// De-allocates *all* memory associated with XMSalloc()ed data
//
int XMSclose (void)
{
if (muCtrlBlks > 0)
{
WORD uCount = muCtrlBlks,
uFreed = 0;
XMSCTRL_T * pXMCtrl = mpXMCtrl + uCount;
do
{
if (XMSfreeBlock(pXMCtrl->uHandle))
uFreed++;
pXMCtrl--;
}
while (uCount-- > 0);
if (uFreed == muCtrlBlks)
{
free(mpXMCtrl);
muCtrlBlks = 0;
muCurrCtrlBlk = 0;
mpXMCtrl = NULL;
return 1;
}
}
return 0;
}
// X M S a l l o c
// ---------------
// Allocate space for data in extended memory
//
// Argument:
//
//
// Returns:
// Handle to memory, or XMSHNULL on error
//
// Notes:
// Overhead is one (WORD) in XMS memory per entry
//
XMSHANDLE XMSalloc (WORD uBytes)
{
XMSCTRL_T * pXMCtrl = mpXMCtrl + muCurrCtrlBlk;
XMSHANDLE xhXM = XMSHNULL;
unsigned uHiWater = pXMCtrl->uHiWater,
uNumK = pXMCtrl->uNumK;
// Word-align
if (uBytes % 2)
uBytes++;
// Check for wrap at 64K boundary
while ((uBytes + uHiWater + sizeof(WORD) < uBytes) ||
((uNumK < 64) &&
(uBytes + uHiWater + sizeof(WORD) > uNumK * 1024)))
{
if (++muCurrCtrlBlk == muCtrlBlks)
return XMSallocPlanB(uBytes);
pXMCtrl++;
uHiWater = pXMCtrl->uHiWater;
uNumK = pXMCtrl->uNumK;
}
xhXM = XMSallocWrite(pXMCtrl->uHandle, uHiWater, uBytes);
if (xhXM != XMSHNULL)
pXMCtrl->uHiWater = uHiWater + uBytes + sizeof(WORD);
else
muCurrCtrlBlk = 0;
return xhXM;
}
// X M S f r e e
// -------------
// Free an allocation unit obtained with XMSalloc()
//
// Arguments:
//
//
// Returns:
// 1 on success, 0 on failure
//
int XMSfree (XMSHANDLE xhXM)
{
XMSBLOCKHEADER_T XMShdr;
XMSMOVE_T XMSmv;
XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
XMSmv.uSrcHdl = (WORD)(xhXM >> 16);
XMSmv.ulSrcOfs = (WORD)xhXM; // Get the length, too
XMSmv.uDestHdl = H_640K;
XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdr);
if (XMSmove(&XMSmv))
{
XMShdr.uData = XMShdr.uLength; // Old len stored in 1st two data bytes
XMShdr.uLength = 0; // Length now marked as zero = reusable
XMSmv.uDestHdl = XMSmv.uSrcHdl;
XMSmv.ulDestOfs = XMSmv.ulSrcOfs; // Write over length bytes
XMSmv.uSrcHdl = H_640K;
XMSmv.ulSrcOfs = (DWORD)((char _far *)&XMShdr);
if (XMSmove(&XMSmv))
{
WORD uBlock;
XMSCTRL_T * pXMCtrl = mpXMCtrl;
for (uBlock = 0; uBlock < muCtrlBlks; uBlock++)
{
if (pXMCtrl->uHandle == XMSmv.uDestHdl)
{
pXMCtrl->fCompacted = FALSE;
break;
}
pXMCtrl++;
}
return 1;
}
}
return 0;
}
// X M S e r r o r C o d e
// -----------------------
// Get the error code associated with the most recent XMS API call
//
WORD XMSerrorCode (void)
{
return muXMSerrCode;
}
// X M S g e t L e n
// -----------------
// Get the length of the space associated with an XMS handle
//
// Arguments:
//
//
// Returns:
// Length of data, or 0 on error
//
WORD XMSgetLen (XMSHANDLE xhXM)
{
WORD hXM = (WORD)(xhXM >> 16),
uOfs = (WORD)xhXM,
uBlock = 0,
uLen = 0;
XMSCTRL_T * pXMCtrl = mpXMCtrl;
while (uBlock < muCtrlBlks && pXMCtrl->uHandle != hXM)
{
uBlock++;
pXMCtrl++;
}
if (uBlock < muCtrlBlks)
{
XMSMOVE_T XMSmv;
XMSmv.ulLength = sizeof(WORD);
XMSmv.uSrcHdl = hXM;
XMSmv.ulSrcOfs = uOfs;
XMSmv.uDestHdl = H_640K;
XMSmv.ulDestOfs = (DWORD)((char _far *)&uLen);
XMSmove(&XMSmv);
}
return uLen;
}
// X M S g e t E x t
// -----------------
// Get data from XMS memory to conventional memory; extended version
//
// Arguments:
//
//
//
//
//
// Returns:
// 1 on success, 0 on failure
//
int XMSgetExt (void * pDest, XMSHANDLE xhXM, WORD uSrcOfs, WORD uBytes)
{
XMSMOVE_T XMSmv;
XMSmv.ulLength = uBytes;
XMSmv.uSrcHdl = (WORD)(xhXM >> 16);
XMSmv.ulSrcOfs = (WORD)xhXM + sizeof(WORD) + uSrcOfs;
XMSmv.uDestHdl = H_640K;
XMSmv.ulDestOfs = (DWORD)((char _far *)pDest);
return XMSmove(&XMSmv);
}
// X M S g e t
// -----------
// Get data from XMS memory to conventional memory
//
// Arguments:
//
//
//
// Returns:
// 1 on success, 0 on failure
//
// Notes:
// Automatically sets number of bytes copied out to the number copied in.
// Caller *must* ensure that buffer at
//
int XMSget (void * pDest, XMSHANDLE xhXM)
{
XMSMOVE_T XMSmv;
XMSmv.ulLength = XMSgetLen(xhXM);
XMSmv.uSrcHdl = (WORD)(xhXM >> 16);
XMSmv.ulSrcOfs = (WORD)xhXM + sizeof(WORD);
XMSmv.uDestHdl = H_640K;
XMSmv.ulDestOfs = (DWORD)((char _far *)pDest);
return XMSmove(&XMSmv);
}
// X M S p u t
// -----------
// Put data in XMS memory from conventional memory
//
// Arguments:
//
//
//
//
// Returns:
// 1 on success, 0 on failure
//
int XMSput (XMSHANDLE xhXM, const void * pSrc, WORD uBytes)
{
XMSMOVE_T XMSmv;
if (uBytes == 0)
uBytes = XMSgetLen(xhXM);
else if (uBytes % 2)
uBytes++;
XMSmv.ulLength = uBytes;
XMSmv.uSrcHdl = H_640K;
XMSmv.ulSrcOfs = (DWORD)((char _far *)pSrc);
XMSmv.uDestHdl = (WORD)(xhXM >> 16);
XMSmv.ulDestOfs = (WORD)xhXM + sizeof(WORD);
return XMSmove(&XMSmv);
}
#if defined ( _M_DEBUG)
// -----------------------------------------------------------------------
// ------------- D e b u g g i n g f u n c t i o n s ---------------
// -----------------------------------------------------------------------
// X M S d u m p C o n t r o l B l o c k
// -------------------------------------
static void _near XMSdumpControlBlock (const XMSCTRL_T * pXMCtrl)
{
printf("%04x %04x (%5u) %04x (%5u)\n", pXMCtrl->uHandle, pXMCtrl->uHiWater,
pXMCtrl->uHiWater, pXMCtrl->uNumK, pXMCtrl->uNumK);
}
// X M S d u m p E x t e n d e d M e m o r y B l o c k
// ---------------------------------------------------
static void _near XMSdumpExtendedMemoryBlock (const XMSCTRL_T * pXMCtrl)
{
XMSMOVE_T XMSmv;
WORD uOfs = 0;
union
{
XMSBLOCKHEADER_T XMShdr;
unsigned char bBuffer[sizeof(WORD) + 16];
}
Data;
if (pXMCtrl->uHiWater == 0) // Has never been used
return;
XMSmv.ulLength = sizeof(Data);
XMSmv.uSrcHdl = pXMCtrl->uHandle;
XMSmv.uDestHdl = H_640K;
XMSmv.ulDestOfs = (DWORD)((char _far *)&Data);
do
{
WORD uRemaining = pXMCtrl->uHiWater - uOfs;
if (uRemaining < sizeof(Data))
XMSmv.ulLength = uRemaining;
XMSmv.ulSrcOfs = uOfs;
if (XMSmove(&XMSmv))
{
WORD i,
iMax = Data.XMShdr.uLength;
if (iMax == 0)
iMax = Data.XMShdr.uData;
if (iMax > 16)
iMax = 16;
printf("%04x: %04x ", uOfs, Data.XMShdr.uLength);
for (i = 0; i < 16; i++)
if (i < iMax)
printf("%02x ", Data.bBuffer[i + sizeof(WORD)]);
else
printf(" ");
printf(" ");
for (i = 0; i < iMax; i++)
{
unsigned char c = Data.bBuffer[i + sizeof(WORD)];
printf("%c", iscntrl(c) ? '.' : c);
}
printf("\n");
}
else
{
printf("ERROR %04x\n", XMSerrorCode());
break;
}
if (Data.XMShdr.uLength == 0)
uOfs += Data.XMShdr.uData;
else
uOfs += Data.XMShdr.uLength;
uOfs += sizeof(WORD);
}
while (uOfs < pXMCtrl->uHiWater &&
(Data.XMShdr.uLength > 0 || Data.XMShdr.uData > 0));
}
// X M S d u m p
// -------------
void XMSdump (WORD uDumpFlags)
{
XMSCTRL_T * pXMCtrl;
WORD uCtrlBlk;
printf("\n*** XMS Dump ***\n\n");
if (uDumpFlags & XMSDUMP_CTRL)
{
printf("Control blocks:\n\n");
printf(" Num: Hdl MaxH (MaxD) NoKH (NoKD)\n");
for (uCtrlBlk = 0, pXMCtrl = mpXMCtrl;
uCtrlBlk < muCtrlBlks;
uCtrlBlk++)
{
printf("%5u: ", uCtrlBlk);
XMSdumpControlBlock(pXMCtrl++);
}
}
if (uDumpFlags & XMSDUMP_DATA)
{
printf("\nExtended memory:");
for (uCtrlBlk = 0, pXMCtrl = mpXMCtrl;
uCtrlBlk < muCtrlBlks;
uCtrlBlk++)
{
printf("\n\nBlock %5u:\n\n", uCtrlBlk);
XMSdumpExtendedMemoryBlock(pXMCtrl++);
}
}
printf("\n****************\n\n");
}
#endif // _M_DEBUG
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/