--- /dev/null
+;-----------------------------------------------------------------------
+;Can't take credit for the ASM code here, found it on a local BBS.
+;The author has beem lost in the mists of time.
+;
+;
+.MODEL MEDIUM
+
+
+ EXTmemError EQU 7
+ XMSmemError EQU 8
+
+
+ ShortAdr EQU 0
+ LongAdr EQU 1
+
+
+procname MACRO Pnam
+ PUBLIC _&Pnam&
+_&Pnam& PROC FAR
+ENDM
+
+endproc MACRO Pnam
+
+_&Pnam& ENDP
+
+ENDM
+
+pwrlolvl_TEXT SEGMENT WORD PUBLIC 'CODE'
+
+ ASSUME CS:pwrlolvl_TEXT, DS:pwrlolvl_TEXT, ES:pwrlolvl_TEXT
+
+SUBTTL (Local Procedure) XMS_setup - find a XMS driver.
+PAGE+
+
+ EVEN
+XMSwordByte LABEL BYTE
+XMSword DW 0
+
+XMSmoveSTRUC STRUC
+
+Length DW 0
+LengthX DW 0
+SrcHandle DW 0
+SrcOffset DW 0
+SrcOffsetX DW 0
+DestHandle DW 0
+DestOffset DW 0
+DestOffsetX DW 0
+
+XMSmoveSTRUC ENDS
+
+XMSmainGET XMSmoveSTRUC <>
+XMSmainPUT XMSmoveSTRUC <>
+XMSwordGET XMSmoveSTRUC <2,,,,,,OFFSET XMSword>
+XMSwordPUT XMSmoveSTRUC <2,,,OFFSET XMSword>
+
+XMSfunctAdr DW 0, 0
+
+
+; Don't try to call this from your programs
+
+XMS_setup PROC NEAR
+
+ PUSH DS
+ PUSH ES
+ PUSH BX
+
+ MOV AX,CS ; Set Data segment to the code
+segment.
+ MOV DS,AX ;
+ MOV [XMSwordGET.DestOffsetX],AX ; Set up the move data
+structures.
+ MOV [XMSwordPUT.SrcOffsetX],AX ;
+
+ MOV AX,4300H ; See if a XMS Driver Exists.
+ INT 2FH ;
+ CMP AL,80H ;
+ MOV AX,0 ;
+ JNE XMS_setup01 ; Return 0 if not.
+
+ MOV AX,4310H ; If so, set the driver's function
+ INT 2FH ; address.
+ MOV [XMSfunctAdr],BX ;
+ MOV [XMSfunctAdr+2],ES ;
+
+ MOV AX,1 ; Return 1.
+
+ XMS_setup01:
+ POP BX
+ POP ES
+ POP DS
+
+ RET
+
+XMS_setup ENDP
+
+
+SUBTTL LSHL - Shift an unsigned long left
+PAGE+
+
+ ;****************************************************************************
+ ;*
+ ;* Shift an unsigned long integer left n number of bits.
+ ;*
+ ;****************************************************************************
+
+ ;
+ ; Stack frame definition for void LSHL( unsigned long *SHLnumber, unsigned n
+);
+ ;
+
+LSHLparms STRUC
+
+ DW 0, 0
+ DW 0
+SHLadr DD ?
+SHLn DW ?
+
+LSHLparms ENDS
+
+procname LSHL
+
+ PUSH BP
+ MOV BP,SP
+
+ PUSH BX
+ PUSH CX
+ PUSH DX
+
+ PUSH DS
+ LDS BX,SHLadr[BP]
+ MOV CX,SHLn[BP]
+
+ MOV AX,[BX] ; Get the long integer.
+ MOV DX,[BX+2] ;
+
+ LSHL_01:
+ SHL AX,1 ; Do the long shift.
+ RCL DX,1 ;
+ LOOP LSHL_01 ;
+
+ MOV [BX],AX ; Replace the addressed number.
+ MOV [BX+2],DX ;
+
+ POP DS
+ POP DX
+ POP CX
+ POP BX
+
+ POP BP
+ RET ; Exit
+
+endproc LSHL
+
+
+SUBTTL Extended Memory - Stack template for EXTget, EXTput
+PAGE+
+
+EXTgpparms STRUC
+
+ DW 0, 0
+ DW 0
+extgpBase DW ?
+extgpblk DW ?
+extgpblkAdr DW ?
+extgpBytes DW ?
+extgpmemAdr DW ?
+ DW ?
+
+EXTgpparms ENDS
+
+
+
+SUBTTL Extended Memory - XMS - Return total XMS memory.
+PAGE+
+
+ ; Use this function to detect wether or not XMS driver installed
+ ;
+ ; Stack frame definition for unsigned XMS_available( void );
+ ;
+ ; The total XMS memory available (in 16k blocks) is returned.
+ ;
+procname XMS_available
+
+ PUSH BX
+ PUSH CX
+ PUSH DX
+
+ CALL XMS_setup ; Ensure XMS memory is set.
+ TEST AX,AX ;
+ JZ XMS_available01 ; Return zero if not.
+
+ MOV AH,08H ; Set the size function code.
+ CALL DWORD PTR CS:[XMSfunctAdr] ; Get the size.
+ TEST AX,AX ;
+ JZ XMS_available01 ;
+
+ MOV AX,DX ; Set available Kbytes.
+ SUB AX,64 ; Subtract out the HMA (HIMEM.SYS
+bug).
+ JNC XMS_available01 ;
+ XOR AX,AX ; Set zero if underflow.
+
+ XMS_available01:
+ MOV CL,4 ; Divide Kbytes by 16 for blocks.
+ SHR AX,CL ;
+
+ POP DX
+ POP CX
+ POP BX
+
+ RET ; Exit
+
+endproc XMS_available
+
+SUBTTL Extended Memory - XMS - Return largest block XMS mem.
+PAGE+
+
+ ;
+ ; Stack frame definition for unsigned XMSblk_available( void );
+ ;
+ ; The size of the largest block of XMS memory available,
+ ; (in 16Kbyte blocks) is returned.
+ ;
+procname XMSblk_available
+
+ PUSH BX
+ PUSH CX
+ PUSH DX
+
+ CALL XMS_setup ; Ensure XMS memory is set.
+ TEST AX,AX ;
+ JZ XMSblk_available01 ; Return zero if not.
+
+ MOV AH,08H ; Set the size function code.
+ CALL DWORD PTR CS:[XMSfunctAdr] ; Get the size.
+ TEST AX,AX ;
+ JZ XMSblk_available01 ;
+
+ SUB DX,64 ; Subtract out the HMA (HIMEM.SYS
+bug).
+ JNC XMSblk_available0X ;
+ XOR DX,DX ; Set zero if underflow.
+
+ XMSblk_available0X:
+ CMP AX,DX ;
+ JBE XMSblk_available01 ;
+ MOV AX,DX ; Set available Kbytes.
+
+ XMSblk_available01:
+ MOV CL,4 ; Divide Kbytes by 16 for blocks.
+ SHR AX,CL ;
+
+ POP DX
+ POP CX
+ POP BX
+
+ RET ; Exit
+
+endproc XMSblk_available
+
+SUBTTL Extended Memory - XMS De-allocate a memory block.
+PAGE+
+
+ ;
+ ; Stack frame definition for int XMS_dealloc( int Hdl );
+ ;
+ ; Zero is returned if the operation fails, non-zero if success.
+ ;
+ ; its really important to do this, only other way to recover
+ ; XMS blocks is to re-boot
+
+XMSdealparms STRUC
+
+ DW 0, 0
+ DW 0
+xmsdealHdl DW ?
+
+XMSdealparms ENDS
+
+
+procname XMS_dealloc
+
+ PUSH BP
+ MOV BP,SP
+
+ PUSH BX
+ PUSH DX
+
+; CALL XMS_setup ; Ensure XMS memory is set.
+; TEST AX,AX ;
+; JZ XMS_dealloc01 ; Return zero if not.
+
+ MOV DX,xmsdealHdl[BP] ; Get the handle to de-allocate.
+ MOV AH,0AH ;
+
+ CALL DWORD PTR CS:[XMSfunctAdr] ; De-allocate it.
+
+ XMS_dealloc01:
+ POP DX
+ POP BX
+
+ POP BP
+ RET ; Exit
+
+endproc XMS_dealloc
+
+SUBTTL Extended Memory - XMS Allocate a memory block.
+PAGE+
+
+ ;
+ ; Stack frame definition for int XMS_alloc( unsigned rsrvd, *size );
+ ;
+ ; rsrved and size are in 16K byte blocks.
+ ; rsrved is mem set aside for EMS, generaly zero
+ ;
+ ; Zero is returned if the operation fails.
+ ; Block (XMS) handle is returned if success.
+ ;
+ ; size - is reduced by the amount of XMS memory actually allocated.
+ ;
+
+XMSalparms STRUC
+
+ DW 0, 0
+ DW 0
+xmsalrsrvd DW ?
+xmsalsize DD ?
+
+XMSalparms ENDS
+
+procname XMS_alloc
+
+ PUSH BP
+ MOV BP,SP
+
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH DI
+ PUSH ES
+ PUSH DS
+
+ MOV AX,CS ; Set the data segment to the code
+ MOV DS,AX ; segment.
+
+ MOV CX,4 ;
+ ADD xmsalrsrvd[BP],CX ; Subtract out the HMA (HIMEM.SYS
+bug).
+ SHL xmsalrsrvd[BP],CL ; Convert reserved blocks to K-bytes.
+
+ LES DI,xmsalsize[BP] ; Load size address.
+ XOR AX,AX ;
+ MOV BX,ES:[DI] ; Get the requested size in blocks.
+
+ TEST BX,0F000H ; Check for more than 64 Megabytes.
+ JZ XMS_alloc01 ;
+ MOV BX,00FFFH ;
+
+ XMS_alloc01:
+ MOV CL,4 ;
+ SHL BX,CL ; Convert to K-Bytes.
+ MOV CX,BX ; In CX.
+ JZ XMS_alloc05 ; Return zero if no size requested.
+
+; CALL XMS_setup ; Ensure XMS memory is set.
+; TEST AX,AX ;
+; JZ XMS_alloc05 ; Return zero if not.
+
+ XOR BX,BX ;
+ MOV AH,08H ; Set to Query Free XMS Memory.
+ CALL DWORD PTR [XMSfunctAdr] ;
+
+ SUB DX,xmsalrsrvd[BP] ; Subtract out reserved blocks.
+ JB XMS_alloc03 ; Ensure no borrow.
+ CMP AX,DX ;
+ JBE XMS_alloc02 ;
+ MOV AX,DX ;
+
+ XMS_alloc02:
+ MOV DX,AX ;
+ CMP AX,68 ; Ensure enough memory to allocate.
+
+ XMS_alloc03:
+ MOV AX,0 ;
+ JB XMS_alloc05 ; Exit if not.
+
+ CMP BL,80H ; Check for errors.
+ JE XMS_alloc05 ;
+ CMP BL,81H ;
+ JE XMS_alloc05 ;
+
+ CMP CX,DX ; Check actual against requested size.
+ JBE XMS_alloc04 ;
+ MOV CX,DX ; Set if actual < requested.
+
+ XMS_alloc04:
+ MOV DX,CX ; Set requested size.
+ MOV AH,09H ;
+ CALL DWORD PTR [XMSfunctAdr] ; Allocate it.
+ DEC AX ; Check for errors.
+ MOV AX,0 ;
+ JNZ XMS_alloc05 ;
+
+
+ MOV AX,CX ; Convert allocated size in KBytes
+ MOV CL,4 ; to allocated blocks.
+ SHR AX,CL ;
+
+ SUB ES:[DI],AX ; Subtract the blocks allocated.
+ MOV AX,DX ; Set to return the handle.
+
+ XMS_alloc05:
+ POP DS
+ POP ES
+ POP DI
+ POP DX
+ POP CX
+ POP BX
+
+ POP BP
+ RET ; Exit
+
+endproc XMS_alloc
+
+SUBTTL Extended Memory - XMS get, put Stack Frame definition
+PAGE+
+
+
+XMSgpparms STRUC
+
+ DW 0, 0
+ DW 0
+xmsgpHdl DW ?
+xmsgpblk DW ?
+xmsgpblkAdr DW ?
+xmsgpBytes DW ?
+xmsgpmemAdr DD ?
+
+XMSgpparms ENDS
+
+SUBTTL Extended Memory - XMStoMem
+PAGE+
+
+
+ ;
+ ; Stack frame definition for int XMStoMem( unsigned Handle,
+ ; unsigned blk,
+ ; unsigned blkAdr,
+ ; unsigned Bytes,
+ ; char *memAdr
+ ; );
+ ;
+ ; XMSmemError is returned if the operation fails, Zero if success.
+ ;
+
+procname XMStoMem
+
+ PUSH BP
+ MOV BP,SP
+
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH SI
+ PUSH DI
+ PUSH ES
+ PUSH DS
+
+ MOV AX,CS ; Set Data Segment to Code Segment.
+ MOV DS,AX ;
+
+ MOV CX,xmsgpBytes[BP] ; Get the number of bytes to transfer.
+ LES BX,xmsgpmemAdr[BP] ; Get the memory address.
+ MOV DX,xmsgpHdl[BP] ; Get the XMS handle.
+ MOV [XMSmainGET.SrcHandle],DX ; Set it in the move structures.
+ MOV [XMSwordGET.SrcHandle],DX ;
+
+ XOR DX,DX ;
+ MOV DI,xmsgpblk[BP] ; Get the block number.
+ SHR DI,1 ; Form the 32 bit XMS address in
+ RCR DX,1 ; DI:DX.
+ SHR DI,1 ;
+ RCR DX,1 ;
+ ADD DX,xmsgpblkAdr[BP] ;
+
+ TEST CX,1 ; Check for an odd number of bytes
+ JZ XMStoMem02 ; to transfer.
+
+ DEC CX ; Decrement to an even number of
+bytes.
+
+ TEST DX,1 ; Check for an odd XMS address.
+ JZ XMStoMem01 ;
+
+ ; XMS address is odd.
+ ; -------------------
+ DEC DX ;
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.
+ MOV [XMSwordGET.SrcOffsetX],DI ;
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.
+
+ PUSH BX ;
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ POP BX ;
+ DEC AX ; Check for errors.
+ JNZ XMStoMem03 ; Error out if error.
+
+ MOV AX,[XMSword] ; Get the moved word.
+
+ MOV ES:[BX],AH ; Move the odd byte to memory.
+
+ INC BX ; Reset the memory address.
+ ADD DX,2 ; And the XMS address.
+
+ JMP XMStoMem02 ; Move the block.
+
+
+ XMStoMem01:
+ ; XMS address is even.
+ ; --------------------
+ ADD DX,CX ;
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.
+ SUB DX,CX ;
+ MOV [XMSwordGET.SrcOffsetX],DI ;
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.
+
+ PUSH BX ;
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ POP BX ;
+ DEC AX ; Check for errors.
+ JNZ XMStoMem03 ; Error out if error.
+
+ MOV AX,[XMSword] ; Get the moved word.
+
+ XCHG DI,CX ;
+ MOV ES:[BX+DI],AL ; Move the odd byte to memory.
+ XCHG DI,CX ;
+
+ XMStoMem02:
+ JCXZ XMStoMem04 ; Avoid a zero byte move.
+
+ MOV XMSmainGET.Length,CX ; Set length for the move.
+
+ MOV XMSmainGET.DestOffset,BX ; Set Memory address.
+ MOV XMSmainGET.DestOffsetX,ES ;
+
+ MOV XMSmainGET.SrcOffset,DX ; Set XMS address.
+ MOV XMSmainGET.SrcOffsetX,DI ;
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSmainGET ; Set address of the move structure.
+
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ DEC AX ; Check for errors.
+ JZ XMStoMem05
+
+ XMStoMem03:
+ MOV AX,XMSmemError ; Set error code if error.
+ JMP XMStoMem05 ;
+
+ XMStoMem04:
+ XOR AX,AX ;
+
+ XMStoMem05:
+ POP DS
+ POP ES
+ POP DI
+ POP SI
+ POP DX
+ POP CX
+ POP BX
+
+ POP BP
+ RET ; Exit
+
+endproc XMStoMem
+
+SUBTTL Extended Memory - MemToXMS
+PAGE+
+
+
+ ;
+ ; Stack frame definition for int MemToXMS( unsigned Handle,
+ ; unsigned blk,
+ ; unsigned blkAdr,
+ ; unsigned Bytes,
+ ; char *memAdr
+ ; );
+ ;
+ ; XMSmemError is returned if the operation fails, Zero if success.
+ ;
+
+procname MemToXMS
+
+ PUSH BP
+ MOV BP,SP
+
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH SI
+ PUSH DI
+ PUSH ES
+ PUSH DS
+
+ MOV AX,CS ;
+ MOV DS,AX ;
+
+ MOV CX,xmsgpBytes[BP] ; Get the number of bytes to transfer.
+ LES BX,xmsgpmemAdr[BP] ; Get the memory address.
+ MOV DX,xmsgpHdl[BP] ; Get the XMS handle.
+ MOV [XMSmainPUT.DestHandle],DX ; Set it in the move structures.
+ MOV [XMSwordPUT.DestHandle],DX ;
+ MOV [XMSwordGET.SrcHandle],DX ;
+
+ XOR DX,DX ;
+ MOV DI,xmsgpblk[BP] ; Get the block number.
+ SHR DI,1 ; Form the 32 bit XMS address in
+ RCR DX,1 ; DI:DX.
+ SHR DI,1 ;
+ RCR DX,1 ;
+ ADD DX,xmsgpblkAdr[BP] ;
+
+ TEST CX,1 ; Check for an odd number of bytes
+ JZ MemToXMS02 ; to transfer.
+
+ DEC CX ; Decrement to an even number of
+bytes.
+
+ TEST DX,1 ; Check for an odd XMS address.
+ JZ MemToXMS01 ;
+
+ ; XMS address is odd.
+ ; -------------------
+ DEC DX ;
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.
+ MOV [XMSwordGET.SrcOffsetX],DI ;
+ MOV [XMSwordPUT.DestOffset],DX ;
+ MOV [XMSwordPUT.DestOffsetX],DI ;
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.
+
+ PUSH BX ;
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ POP BX ;
+ DEC AX ; Check for errors.
+ JNZ MemToXMS03 ; Error out if error.
+
+ MOV AH,ES:[BX] ; Get the odd memory byte.
+
+ MOV [XMSwordByte+1],AH ; Put it in the moved word.
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSwordPUT ; Set address of the move structure.
+
+ PUSH BX ;
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ POP BX ;
+ DEC AX ; Check for errors.
+ JNZ MemToXMS03 ; Error out if error.
+
+ INC BX ; Reset the memory address.
+ ADD DX,2 ; And the XMS address.
+
+ JMP MemToXMS02 ; Move the block.
+
+ MemToXMS01:
+ ; XMS address is even.
+ ; --------------------
+ ADD DX,CX ;
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.
+ MOV [XMSwordPUT.DestOffset],DX ;
+ SUB DX,CX ;
+ MOV [XMSwordGET.SrcOffsetX],DI ;
+ MOV [XMSwordPUT.DestOffsetX],DI ;
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.
+
+ PUSH BX ;
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ POP BX ;
+ DEC AX ; Check for errors.
+ JNZ MemToXMS03 ; Error out if error.
+
+ XCHG DI,CX ;
+ MOV AL,ES:[BX+DI] ; Get the odd memory byte.
+ XCHG DI,CX ;
+
+ MOV [XMSwordByte],AL ; Set the moved word.
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSwordPUT ; Set address of the move structure.
+
+ PUSH BX ;
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ POP BX ;
+ DEC AX ; Check for errors.
+ JNZ MemToXMS03 ; Error out if error.
+
+ MemToXMS02:
+ JCXZ MemToXMS04 ; Avoid a zero byte move.
+
+ MOV XMSmainPUT.Length,CX ; Set length for the move.
+
+ MOV XMSmainPUT.SrcOffset,BX ; Set Memory address.
+ MOV XMSmainPUT.SrcOffsetX,ES ;
+
+ MOV XMSmainPUT.DestOffset,DX ; Set XMS address.
+ MOV XMSmainPUT.DestOffsetX,DI ;
+
+ MOV AH,0BH ; Set the XMS move, function code.
+ MOV SI,OFFSET XMSmainPUT ; Set address of the move structure.
+
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.
+ DEC AX ; Check for errors.
+ JZ MemToXMS05
+
+ MemToXMS03:
+ MOV AX,XMSmemError ; Set error code if error.
+ JMP MemToXMS05 ;
+
+ MemToXMS04:
+ XOR AX,AX ;
+
+ MemToXMS05:
+ POP DS
+ POP ES
+ POP DI
+ POP SI
+ POP DX
+ POP CX
+ POP BX
+
+ POP BP
+ RET ; Exit
+
+endproc MemToXMS
+
+
+SUBTTL Last Page
+PAGE+
+
+pwrlolvl_TEXT ENDS
+
+ END
+
--- /dev/null
+/*
+ Written by Alexander J. Russell 1994
+
+ Placed in the public Domain by Alec Russell, March 1995
+
+ Slightly higher level xms calls than xmem.asm
+
+*/
+
+#include <stdio.h>
+#include <io.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "src\lib\xmem\xmem.h"
+
+xms_head_t xms_head={0}; // set handle to zero
+
+
+/* ---------------------- alloc_xms() ----------------- February 19,1994 */
+short alloc_xms(unsigned short far *size) // size in 16k blocks
+{
+ return(XMS_alloc(0, size));
+}
+
+
+
+/* ---------------------- xms_to_mem() ---------------- February 19,1994 */
+short xms_to_mem(unsigned short handle, void far *p, unsigned long off,
+unsigned short n)
+{
+ unsigned short block, boff;
+
+ block=off >> XMSBLOCKSHIFT;
+ boff=off - (block << XMSBLOCKSHIFT);
+
+ return(XMStoMem(handle, block, boff, n, p));
+}
+
+
+/* ---------------------- mem_to_xms() ---------------- February 19,1994 */
+short mem_to_xms(unsigned short handle, void far *p, unsigned long off,
+unsigned short n)
+{
+ unsigned short block, boff;
+
+ block=off >> XMSBLOCKSHIFT;
+ boff=off - (block << XMSBLOCKSHIFT);
+
+ return(MemToXMS(handle, block, boff, n, p));
+}
+
+
+/* ---------------------- qalloc_xms() -------------------- March 8,1994 */
+xms_node_t *qalloc_xms(unsigned long size)
+{
+ xms_node_t *node=NULL;
+ xms_node_t *t1;
+
+ if ( size <= xms_head.avail )
+ {
+ // look for existing node
+ t1=xms_head.next;
+ while ( t1 )
+ {
+ if ( t1->used == 0 && t1->size >= size )
+ {
+ t1->off=0;
+ t1->used=1;
+ node=t1;
+ break;
+ }
+ else
+ t1=t1->next;
+ }
+
+ if ( node == NULL ) // didn't find existing node
+ {
+ node=malloc(sizeof(xms_node_t));
+ if ( node )
+ {
+ node->off=0;
+ node->used=1;
+ node->size=size;
+ node->next=NULL;
+ node->start=xms_head.next_off;
+ xms_head.avail-=size;
+ xms_head.next_off+=size;
+ if ( xms_head.next == NULL )
+ {
+ xms_head.next=node;
+ }
+ else
+ {
+ t1=xms_head.next;
+ while ( t1->next )
+ t1=t1->next;
+ t1->next=node;
+ }
+ }
+ else
+ printf("out of near mem in qalloc_xms");
+ }
+ }
+ else
+ printf("out of xms mem in qalloc size %lu avail %lu", size,
+xms_head.avail);
+
+ return(node);
+}
+
+
+/* ---------------------- qfree_xms() --------------------- March 8,1994 */
+void qfree_xms(xms_node_t *node)
+{
+ xms_node_t *t1;
+
+ if ( xms_head.next )
+ {
+ t1=xms_head.next;
+ while ( t1 != node && t1 )
+ t1=t1->next;
+
+ if ( t1 )
+ {
+ t1->used=0;
+ }
+ else
+ printf("ERROR didn't find node qfree");
+ }
+ else
+ {
+ printf("ATTEMPTED to qfree empty list");
+ }
+}
+
+
+
+/* ---------------------- xms_open() ---------------------- March 8,1994 */
+xms_node_t *xms_open(char *file)
+{
+ int i;
+ xms_node_t *node=NULL;
+ FILE *fp;
+ char *buffer;
+ unsigned long off;
+
+ fp=fopen(file, "rb");
+ if ( fp )
+ {
+ node=qalloc_xms(filelength(fileno(fp)));
+ if ( node )
+ {
+ buffer=malloc(4096);
+ if ( buffer )
+ {
+ off=0l;
+ while ( (i=fread(buffer, 1, 4096, fp)) )
+ {
+ mem_to_xms(xms_head.handle, (char far *)buffer,
+off+node->start, i);
+ off+=i;
+ }
+
+ free(buffer);
+ }
+ else
+ printf("out of mem in xms_open 1");
+ }
+
+ fclose(fp);
+ }
+ else
+ printf("ERROR opening %s in xms_open", file);
+
+ return(node);
+}
+
+
+/* ---------------------- xms_read() ---------------------- March 8,1994 */
+short xms_read(void far *buffer, unsigned short n, xms_node_t *node)
+{
+
+ if ( node->off >= node->size )
+ return 0;
+
+ if ( n+node->off > node->size )
+ n=node->size - node->off;
+
+ xms_to_mem(xms_head.handle, buffer, node->start+node->off, n);
+ node->off+=n;
+
+ return(n);
+}
+
+
+/* ---------------------- xms_write() ---------------------- March 8,1994 */
+short xms_write(void far *buffer, unsigned short n, xms_node_t *node)
+{
+
+ if ( node->off >= node->size )
+ return 0;
+
+ if ( n+node->off > node->size )
+ n=node->size - node->off;
+
+ mem_to_xms(xms_head.handle, buffer, node->start+node->off, n);
+ node->off+=n;
+
+ return(n);
+}
+
+
+/* ---------------------- xms_tell() ---------------------- March 8,1994 */
+long xms_tell(xms_node_t *node)
+{
+ return node->off;
+}
+
+
+
+/* ---------------------- xms_seek() ---------------------- March 8,1994 */
+short xms_seek(xms_node_t *node, long off, short whence)
+{
+ short err=0;
+
+ switch ( whence )
+ {
+ case SEEK_SET:
+ if ( off < 0l || off > node->size )
+ err=1;
+ else
+ node->off=off;
+ break;
+
+ case SEEK_END:
+ if ( off > 0l || (node->size + off) < 0l )
+ err=1;
+ else
+ node->off=node->size + off;
+ break;
+
+ case SEEK_CUR:
+ if ( node->off + off < 0l || node->off + off > node->size )
+ err=1;
+ else
+ node->off+=off;
+ break;
+ }
+
+ return(err);
+}
+
+
+/* ---------------------- xms_close() --------------------- March 8,1994 */
+void xms_close(xms_node_t *node)
+{
+ qfree_xms(node);
+}
+
+
+
+
+/* ---------------------- init_xms() ---------------------- March 8,1994 */
+short init_xms(unsigned short min_blocks)
+{
+ unsigned short blocks;
+
+ blocks=XMSblk_available();
+ if ( blocks >= min_blocks )
+ {
+ memset(&xms_head, 0, sizeof(xms_head_t));
+ if ( (xms_head.handle=alloc_xms(&blocks)) )
+ {
+ printf("blocks minus by = %u", blocks);
+ min_blocks-=blocks;
+ xms_head.avail=xms_head.total=(unsigned long)min_blocks*XMSBLOCK;
+ blocks=min_blocks;
+ }
+ else
+ blocks=0;
+ }
+ else
+ blocks=0;
+
+ return(blocks);
+}
+
+
+/* ---------------------- deinit_xms() -------------------- March 8,1994 */
+void deinit_xms(void)
+{
+ xms_node_t *t1, *t2;
+
+ if ( xms_head.handle )
+ {
+ XMS_dealloc(xms_head.handle);
+ if ( xms_head.next )
+ {
+ t1=xms_head.next;
+ t2=t1->next;
+ while ( t1 )
+ {
+ free(t1);
+ t1=t2;
+ t2=t1->next;
+ }
+ }
+
+ memset(&xms_head, 0, sizeof(xms_head_t));
+ }
+}
+
+
+
+/* --------------------------- end of file ------------------------- */