'
' NeoLib - VXMS Module
'
' Features:
'  6 subs
'  3 functions
' For a total of: 9 routines
'
' Specially designed and coded for AAP's QBCPC
' Official Library of the QuickBASIC Caliber Programming Compo (Summer & Autumn 2003)
'
DECLARE FUNCTION neoVXMSinit% ()
DECLARE FUNCTION neoVXMSalloc% (KBytes AS LONG)
DECLARE FUNCTION neoVXMSfree& ()

DECLARE SUB neoVXMSdealloc (Handle AS INTEGER)
DECLARE SUB neoVXMSrealloc (Handle AS INTEGER, KBytes AS LONG)
DECLARE SUB neoVXMSread (Handle AS INTEGER, Offset AS LONG, DataLength AS LONG, BufferSeg AS INTEGER, BufferOff AS INTEGER)
DECLARE SUB neoVXMSwrite (BufferSeg AS INTEGER, BufferOff AS INTEGER, Handle AS INTEGER, Offset AS LONG, DataLength AS LONG)
DECLARE SUB neoVXMSmove (FirstHandle AS INTEGER, FirstOffset AS LONG, SecondHandle AS INTEGER, SecondOffset AS LONG, DataLength AS LONG)
DECLARE SUB neoVXMSexchange (FirstHandle AS INTEGER, FirstOffset AS LONG, SecondHandle AS INTEGER, SecondOffset AS LONG, DataLength AS LONG)

DEFINT A-Z
'$DYNAMIC
'$INCLUDE: 'QB.BI'
'$INCLUDE: 'neoEMS.bi'

'////////////////////////////////////////////////////////////////////////////
' FUNCTIONS
'////////////////////////////////////////////////////////////////////////////
FUNCTION neoVXMSinit
	'returns -1 or 0, whether Virtual XMS can be used

	IF NOT neoEMSexist THEN neoVXMSinit = 0: EXIT FUNCTION

        IF neoEMSfreePages = 0 OR neoEMSfreeHandles = 0 THEN neoVXMSinit = 0: EXIT FUNCTION

        neoVXMSinit = -1
END FUNCTION

FUNCTION neoVXMSalloc (KBytes AS LONG)
	'allocates the specified amount of KBytes of Virtual XMS, then returns the handle to Virtual XMS
	'- KBytes: The number of kilobytes to allocate

        tmpP# = CDBL(KBytes) / 16
        IF INT(tmpP#) = tmpp# THEN Pages = INT(tmpP#) ELSE Pages = INT(tmpP# + 1)

        Hand% = neoEMSalloc(Pages)
        neoVXMSalloc = Hand%
END FUNCTION

FUNCTION neoVXMSfree&
	'returns the amount of KBytes free Virtual XMS

	neoVXMSfree& = neoEMSfreePages * 16&
END FUNCTION

'////////////////////////////////////////////////////////////////////////////
' SUBS
'////////////////////////////////////////////////////////////////////////////
SUB neoVXMSdealloc (Handle AS INTEGER)
	'frees the Virtual XMS with the specified Handle
	'- Handle: the handle of the VXMS to free

	neoEMSdealloc Handle
END SUB

SUB neoVXMSrealloc (Handle AS INTEGER, KBytes AS LONG)
	'reallocates Virtual XMS to the specified Handle
	'- Handle: the handle of the VXMS to resize
	'- KBytes: the new size of the VXMS

	tmpP# = CDBL(KBytes) / 16
	IF INT(tmpP#) = tmpP# THEN Pages = INT(tmpP#) ELSE Pages = INT(tmpP# + 1)

	neoEMSrealloc Handle, Pages
END SUB

SUB neoVXMSread (Handle AS INTEGER, Offset AS LONG, DataLength AS LONG, BufferSeg AS INTEGER, BufferOff AS INTEGER)
        'reads from Virtual XMS and stores the read data in a buffer
        '- Handle: the VXMS to read from
        '- Offset: the offset to begin reading
        '- DataLength: the amount of bytes to read
        '- BufferSeg: the segment of the base-buffer
        '- BufferOff: the offset of the base-buffer

        NowPage = Offset \ 16384
        NowOffset = Offset MOD 16384

	NowWriteOffset = BufferOff
        gotnow& = 0

        DO UNTIL gotnow& = DataLength
                MaxBLen = 16384 - NowOffset
                IF gotnow& + MaxBLen > DataLength THEN MaxBLen = DataLength - gotnow&

                neoEMSmove Handle, NowPage, NowOffset, 0, BufferSeg, NowWriteOffset, CLNG(MaxBLen)

		gotnow& = gotnow& + MaxBLen
                NowOffset = NowOffset + MaxBLen
                NowWriteOffset = NowWriteOffset + MaxBLen
                IF NowOffset = 16384 THEN NowOffset = 0: NowPage = NowPage + 1
        LOOP
END SUB

SUB neoVXMSwrite (BufferSeg AS INTEGER, BufferOff AS INTEGER, Handle AS INTEGER, Offset AS LONG, DataLength AS LONG)
        'writes to Virtual XMS and stores the data in VXMS
        '- BufferSeg: the source data's Segment address
        '- BufferOff: the source data's Offset address
        '- Handle: the handle of the VXMS to write to
        '- Offset: the starting offset in VXMS to write data to
        '- DataLength: the amount of bytes to write

	NowPage = Offset \ 16384
	NowOffset = Offset MOD 16384

	NowReadOffset = BufferOff
	gotnow& = 0

	DO UNTIL gotnow& = DataLength
		MaxBLen = 16384 - NowOffset
		IF gotnow& + MaxBLen > DataLength THEN MaxBLen = DataLength - gotnow&

		neoEMSmove 0, BufferSeg, NowReadOffset, Handle, NowPage, NowOffset, CLNG(MaxBLen)

		gotnow& = gotnow& + MaxBLen
		NowOffset = NowOffset + MaxBLen
		NowReadOffset = NowReadOffset + MaxBLen
		IF NowOffset = 16384 THEN NowOffset = 0: NowPage = NowPage + 1
	LOOP
END SUB

SUB neoVXMSmove (FirstHandle AS INTEGER, FirstOffset AS LONG, SecondHandle AS INTEGER, SecondOffset AS LONG, DataLength AS LONG)
        'copies a Virtual XMS region to another Virtual XMS region
        '- FirstHandle: the handle of the source XMS region
        '- FirstOffset: the offset to begin reading with
        '- SecondHandle: the handle of the destination XMS region
        '- SecondOffset: the offset to begin writing at
        '- DataLength: the amount of bytes to copy

        gotnow& = 0
        NowOff1& = FirstOffset
        NowOff2& = SecondOffset

        pF% = neoEMSpageFrame

        DO UNTIL gotnow& = DataLength
                MaxBLen& = 65536&
                IF gotnow& + MaxBLen& > DataLength THEN MaxBLen& = DataLength - gotnow&

		neoVXMSread FirstHandle, NowOff1&, MaxBLen&, pF%, 0
		neoVXMSwrite pF%, 0, SecondHandle, NowOff2&, MaxBLen&

		NowOff1& = NowOff1& + MaxBLen&
		NowOff2& = NowOff2& + MaxBLen&
		gotnow& = gotnow& + MaxBLen&
        LOOP
END SUB

SUB neoVXMSexchange (FirstHandle AS INTEGER, FirstOffset AS LONG, SecondHandle AS INTEGER, SecondOffset AS LONG, DataLength AS LONG)
	'exchanges data within Virtual XMS
	'- FirstHandle: the handle of an VXMS region
	'- FirstOffset: the offset to start swapping with
	'- SecondHandle: the handle of another VXMS region
	'- SecondOffset: the offset to start swapping with
	'- DataLength: the amount of bytes to swap

	gotnow& = 0
        NowOff1& = FirstOffset
        NowOff2& = SecondOffset

	pF% = neoEMSpageFrame

	DO UNTIL gotnow& = DataLength
                MaxBLen& = 2000&
                IF gotnow& + MaxBLen& > DataLength THEN MaxBLen& = DataLength - gotnow&

                neoVXMSread FirstHandle, NowOff1&, MaxBLen&, pF%, 0
                neoVXMSread SecondHandle, NowOff2&, MaxBLen&, pF%, 2000

                neoVXMSwrite pF%, 0, SecondHandle, NowOff2&, MaxBLen&
                neoVXMSwrite pF%, 2000, FirstHandle, NowOff1&, MaxBLen&

                NowOff1& = NowOff1& + MaxBLen&
                NowOff2& = NowOff2& + MaxBLen&
                gotnow& = gotnow& + MaxBLen&
	LOOP
END SUB
