home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
windows
/
mlocal.zip
/
LISTMGR.ASM
next >
Wrap
Assembly Source File
|
1991-03-16
|
38KB
|
1,001 lines
PAGE 60, 132
;------------------------------------------------------------------------------
; Linked List Manager Routines 386 only!!!!!
; Dan Quigley 11-11-90
;------------------------------------------------------------------------------
IF1
%OUT Linked List Manager Routines 386 only!!!!
ENDIF
;;;DEBUG EQU 1
DUMP EQU 1
IFDEF DUMP
IF1
%OUT ListMgr: dump routines enabled
ENDIF
DumpOutW MACRO st,wTmp,wSz ; dump word
mov di,offset DGROUP:st
add di, wSz
FarPtr lpStr, es, di
cCall Hex16Cvt <wTmp,lpStr>
ENDM
DumpOutD MACRO st,lpTmp,wSz ; dump dword
mov di,offset DGROUP:st
add di,wSz
mov cx,wptr lpTmp+2
cCall Hex16Cvt <cx,es,di>
add di,4
mov cx,wptr lpTmp
cCall Hex16Cvt <cx,es,di>
ENDM
; dump far pointer
DumpOutA MACRO st,lpTmp,wSz
mov di,offset DGROUP:st
add di,wSz
mov cx,wptr lpTmp+2
cCall Hex16Cvt <cx,es,di>
add di,5
mov cx,wptr lpTmp
cCall Hex16Cvt <cx,es,di>
ENDM
DebugOut MACRO st ; dump string
pushad
mov ax,SEG _DATA
push ax
push offset DGROUP:st
cCall OUTPUTDEBUGSTRING
popad
ENDM
ENDIF ; IFDEF DUMP
IFDEF DEBUG
IF1
%OUT ListMgr: debug routines enabled
ENDIF
DebugBreak MACRO
int 1
ENDM
ENDIF
;------------------------------------------------------------------------------
; Equates and structures
;------------------------------------------------------------------------------
jmps EQU <jmp short> ; Helper equates
bptr EQU <byte ptr>
wptr EQU <word ptr>
dwptr EQU <dword ptr>
DList struc
dwPrev dd ?
dwNext dd ?
DList ends
ListStruc struc
wListSize dw ? ; size of list record - link
dwListCount dd ? ; Count of records in list
hListTop dd ? ; FarLocal handle to top
hListEnd dd ? ; FarLocal handle to end
lpCompare dd ? ; Compare proc for sort/search
hListDS dw ? ; callers ds
ListStruc ends
;------------------------------------------------------------------------------
; CMACRO Setup
;------------------------------------------------------------------------------
.xlist ; Suspend listing
?DF = 1 ; Don't generate default segs
?PLM = 1 ; Support Pascal calling
?WIN = 1 ; Support WINDOWS
include cmacros.inc
include windows.inc
.list
LISTMEM EQU (LMEM_FIXED OR LMEM_ZEROINIT)
;------------------------------------------------------------------------------
; Segment definitions
;------------------------------------------------------------------------------
createSeg LISTMGR_TEXT,CODE,PARA,PUBLIC,CODE ; Define code segment
IFDEF DUMP
createSeg _DATA,DATA,PARA,PUBLIC,DATA,DGROUP ; Define data segment
defGrp DGROUP,DATA ; Declare DGROUP
assumes DS,DATA ; Tell assembler where DS is
;------------------------------------------------------------------------------
; Global variables
;------------------------------------------------------------------------------
sBegin DATA
staticD holdrand,1
staticW wNodeCount, 0
staticB DumpHdr0,<'wListSize : ',13,10,0>
staticB DumpHdr1,<'dwCount : ',13,10,0>
staticB DumpHdr2,<'hListTop : : ',13,10,0>
staticB DumpHdr3,<'hListEnd : : ',13,10,0>
staticB NodesHdr,<'Node Previous Next',13,10,0>
staticB NodeList,<' : : ',13,10,0>
sEnd DATA
ENDIF ; IFDEF DUMP
;------------------------------------------------------------------------------
; External procedures
;------------------------------------------------------------------------------
externFP <FARLOCALALLOC>
externFP <FARLOCALFREE>
externFP <OUTPUTDEBUGSTRING>
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
.386 ; Enable 386 instruction set
sBegin CODE
assumes CS,CODE ; Reference CS
IFDEF DUMP
;------------------------------------------------------------------------------
; Hex16Cvt - Converts 16-bit binary to ascii Hex
;
; Returns : Nothing
;------------------------------------------------------------------------------
cProc Hex16Cvt,<NEAR>,<es,di>
parmW wNum
parmD lStr
cBegin
les di, lStr
mov dx, wNum
mov cx, 4
HCLoop: push cx
mov cl, 4
rol dx, cl
mov al, dl
and al,00Fh
daa
add al,0F0h
adc al,040h
stosb
pop cx
loop HCLoop
cEnd
;------------------------------------------------------------------------------
; DumpNode - Dumps a Node to the debug monitor
; : bx = record length
;
; Returns : Nothing
;------------------------------------------------------------------------------
cProc DumpNode,<NEAR>,<ds,es>
parmD hNode
cBegin
pushad
mov ax,SEG _DATA
mov es,ax
DumpOutW NodeList, es:wNodeCount,0
lds si, hNode
add si, bx
DumpOutA NodeList, [si].dwPrev, 11
DumpOutA NodeList, [si].dwNext, 21
DebugOut NodeList
popad
cEnd
;------------------------------------------------------------------------------
; ListDump - Dumps a list to the debug monitor
;
; Returns : Nothing
;------------------------------------------------------------------------------
cProc ListDump,<PUBLIC,FAR>,<es,ds,si,di>
parmD hList
cBegin
mov ax,SEG _DATA
mov es,ax
mov es:wNodeCount,1 ; initialize node counter
lds si,hList ; access list header
DumpOutW DumpHdr0,[si].wListSize,11
DumpOutD DumpHdr1,[si].dwListCount,11
DumpOutA DumpHdr2,[si].hListTop,11
DumpOutA DumpHdr3,[si].hListEnd,11
DebugOut DumpHdr0
DebugOut DumpHdr1
DebugOut DumpHdr2
DebugOut DumpHdr3
DebugOut NodesHdr
mov bx,[si].wListSize
mov eax,[si].hListTop
cmp eax,0
je LDExit
cCall DumpNode <eax>
mov ecx,[si].hListEnd
lds si,[si].hListTop
LDLoop: cmp eax,ecx ; are we at the end
je LDExit ; yes
inc es:wNodeCount ; bump the node count
mov eax,[si+bx].dwNext
lds si,[si+bx].dwNext ; get the next node
cCall DumpNode <eax>
jmps LDLoop
LDExit:
cEnd
ENDIF ;IFDEF DUMP
;------------------------------------------------------------------------------
; ListAllocNode - Allocates memory for a new node
;
; Returns : DX:AX = Handle to node
;------------------------------------------------------------------------------
cProc ListAllocNode,<PUBLIC,FAR>,<ds,si>
parmD hList
cBegin
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
mov ax,[si].hListDS ; get ds of calling app
mov ds,ax ; and reset it for alloc
add bx,size DList ; add space for our pointers
mov ax,LISTMEM ; allocation flags
cCall FARLOCALALLOC <ax,bx> ; allocate a record
cEnd
;------------------------------------------------------------------------------
; ListCreate - Creates a linked list
;
; Returns : DX:AX = Handle to list
;------------------------------------------------------------------------------
cProc ListCreate,<PUBLIC,FAR>,<ds,si>
parmW wRecSize
cBegin
mov ax,LISTMEM
mov cx,size ListStruc
cCall FARLOCALALLOC <ax,cx> ; allocate a header
cmp dx,0 ; success?
je LIExit ; no then exit
push ds ; save tasks ds
mov ds,dx ; ds:si ---> header
mov si,ax
mov ax,wRecSize ; retrieve and
test ax,1 ; insure word alignment
jz LCEven ; for faster sorts on large
inc ax ; records
LCEven: mov [si].wListSize, ax ; store the record size
pop ax ; store the calling tasks ds
mov [si].hListDS,ax
mov ax,si
LIExit:
cEnd
;------------------------------------------------------------------------------
; ListIsNodeLast - Test to determine if we are at the end of the list
;
; Returns : AX = TRUE if at the end of the list
;------------------------------------------------------------------------------
cProc ListIsNodeLast,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD dwNode
cBegin
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
mov eax,[si].hListEnd
cmp eax, dwNode
je LINLIsEnd
mov ax, FALSE
jmps LINLExit
LINLIsEnd: mov ax, TRUE
LINLExit:
cEnd
;------------------------------------------------------------------------------
; ListIsNodeFirst - Test to determine if we are at the top of the list
;
; Returns : AX = TRUE if at the end of the list
;------------------------------------------------------------------------------
cProc ListIsNodeFirst,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD dwNode
cBegin
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
mov eax,[si].hListTop
cmp eax,dwNode
je LINFIsTop
mov ax, FALSE
jmps LINFExit
LINFIsTop: mov ax, TRUE
LINFExit:
cEnd
;------------------------------------------------------------------------------
; ListGetFirstNode - Gets the First record in a list
;
; Returns : DX:AX Handle to the record
;------------------------------------------------------------------------------
cProc ListGetFirstNode,<PUBLIC,FAR>,<ds,si>
parmD hList
cBegin
lds si,hList ; access list header
cmp dwptr [si].hListTop,0 ; is there a list yet?
je LGFNErr
lds si,[si].hListTop ; get the first node
mov ax,si
mov dx,ds
jmps LGFNExit
LGFNErr: mov ax,0
mov dx,0
LGFNExit:
cEnd
;------------------------------------------------------------------------------
; ListGetNodeCount - Gets the record count in a list
;
; Returns : DX:AX count
;------------------------------------------------------------------------------
cProc ListGetNodeCount,<PUBLIC,FAR>,<ds,si>
parmD hList
cBegin
lds si,hList ; access list header
cmp dwptr [si].hListTop,0 ; is there a list yet?
je LGNCErr
mov ax,wptr [si].dwListCount
mov dx,wptr [si].dwListCount+2
jmps LGNCExit
LGNCErr: mov ax, 0
mov dx, 0
LGNCExit:
cEnd
;------------------------------------------------------------------------------
; ListGetLastNode - Gets the Last Node in a list
;
; Returns : DX:AX Handle to the record
;------------------------------------------------------------------------------
cProc ListGetLastNode,<PUBLIC,FAR>,<ds,si>
parmD hList
cBegin
lds si,hList ; access list header
cmp dwptr [si].hListEnd,0 ; is there a list yet?
je LGLNErr
lds si,[si].hListEnd ; get the last node
mov dx,ds
mov ax,si
jmps LGLNExit
LGLNErr: mov ax, 0
mov dx, 0
LGLNExit:
cEnd
;------------------------------------------------------------------------------
; ListGetNextNode - Gets the Next record in a list
;
; Returns : DX:AX Handle to the record
;------------------------------------------------------------------------------
cProc ListGetNextNode,<PUBLIC,FAR>,<ds,si>
parmD hList
parmD dwNode
cBegin
IFDEF DEBUG
DebugOut ListGetNextNode
DebugBreak
ENDIF
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
cCall ListIsNodeLast <hList,dwNode>
cmp ax,0 ; is current the last node
jne LGNNErr ; yes
lds si,dwNode ; get the current node
lds si,[si+bx].dwNext ; no, load the record
mov dx,ds
mov ax,si
jmps LGNNExit
LGNNErr: mov dx,0
mov ax,0 ; signal failure
LGNNExit:
cEnd
;------------------------------------------------------------------------------
; ListGetPrevNode - Gets the Previous record in a list
;
; Returns : DX:AX Handle to the record
;------------------------------------------------------------------------------
cProc ListGetPrevNode,<PUBLIC,FAR>,<ds,si>
parmD hList
parmD dwNode
cBegin
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
cCall ListIsNodeFirst <hList,dwNode>
cmp ax,0 ; is this the First node
jne LGPNErr ; yes
lds si, dwNode
lds si,[si+bx].dwPrev
mov dx, ds
mov ax, si
jmps LGPNExit
LGPNErr: mov dx,0
mov ax,0 ; signal failure
LGPNExit:
cEnd
;------------------------------------------------------------------------------
; ListGetNode - Gets the nth record of a list
;
; Returns : DX:AX Handle to the record
;------------------------------------------------------------------------------
cProc ListGetNode,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD dwNode
cBegin
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
mov ecx,dwNode ; get the requested record #
jecxz LGNPastEnd ; zero records
cmp ecx,[si].dwListCount ; greater than count
ja LGNPastEnd
lds si,[si].hListTop ; get the first record
dec ecx
jz LGNIsRec ; just one record
LGNTop: lds si,[si+bx].dwNext
db 66h ; force LOOP on ECX
loop LGNTop
LGNIsRec: mov dx, ds
mov ax, si
jmps LGNExit
LGNPastEnd: mov dx, 0
mov ax, 0 ; assume failure
LGNExit:
cEnd
;------------------------------------------------------------------------------
; ListSwapNode - Swaps positions of two nodes by copying data not pointers
;
; Returns : AX = NONZERO = Success
;------------------------------------------------------------------------------
cProc ListSwapNode,<PUBLIC,FAR>,<cx,es,ds,si,di>
parmD hList
parmD dwNode1
parmD dwNode2
cBegin
cmp dwptr dwNode1,0 ; nullcheck pointer
je LSNErr
cmp dwptr dwNode2,0
je LSNErr
lds si,hList ; access list header
mov cx,[si].wListSize ; get the record size
shr cx,1 ; move words
jcxz LSNExit
lds si,dwNode1
les di,dwNode2
cld ; clear direction flag
LSNLoop: mov ax,es:[di]
xchg [si],ax
stosw
add si,2
loop LSNLoop
mov ax,TRUE ; signal success
jmps LSNExit
LSNErr: mov ax,FALSE
LSNExit:
cEnd
;------------------------------------------------------------------------------
; ListAddNode - Adds a Node to the end of the designated list
;
; Returns : AX = NONZERO = success
;------------------------------------------------------------------------------
cProc ListAddNode,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD pNode
cBegin
mov eax,pNode
cmp eax,0 ; null pointer check
je LANExit
lds si, hList
mov bx,[si].wListSize ; get the record size
inc [si].dwListCount ; bump record count
cmp dwptr [si].hListTop,0 ; is this the first node?
jne LANSkip
mov [si].hListTop,eax ; initialize top and end ptrs
mov [si].hListEnd,eax ; set the new list end
lds si,pNode ; address new node
mov [si+bx].dwPrev,eax
mov [si+bx].dwNext,eax
jmps LANDone
LANSkip: les di,[si].hListEnd ; address last record
mov [si].hListEnd,eax ; set the new list end
lds si,pNode ; address new node
push es:[di+bx].dwNext ; save the last record handle
mov es:[di+bx].dwNext,eax ; save the new record as next
mov [si+bx].dwNext,eax ; last record points to itself
pop [si+bx].dwPrev ; former last is prev now
LANDone: mov ax, TRUE
LANExit:
cEnd
;------------------------------------------------------------------------------
; ListAllocAddNode - Allocs and Adds a Node to the end of the designated list
; copies the passed node parameter to the newly alloc'd
;
; Returns : AX = NONZERO = success
;------------------------------------------------------------------------------
cProc ListAllocAddNode,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD pNode
cBegin
mov eax,hList
cCall LISTALLOCNODE <eax>
cmp dx,0
je LAAError
lds si,hList ; copy the passed node
mov cx,[si].wListSize ; to the newly alloc'd
lds si,pNode
mov es,dx
mov di,ax
repnz movsb
cCall LISTADDNODE <hList,dx,ax>
jmps LAAExit
LAAError: mov ax, TRUE
LAAExit:
cEnd
;------------------------------------------------------------------------------
; ListDeleteNode - Deletes a Node in designated list
;
; Returns : AX = NONZERO = success
;------------------------------------------------------------------------------
cProc ListDeleteNode,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD pNode
cBegin
mov eax, pNode
cmp eax, 0
je LDNExit
lds si,hList ; access list header
mov edx,[si].hListEnd ; edx ---> hListEnd
cmp edx,0 ; is there no list at all
je LDNFreNode ; yes, just free the node
mov ecx,[si].hListTop ; ecx ---> hListTop
mov bx,[si].wListSize ; bx ---> wListSize
dec [si].dwListCount ; decrement count
cmp eax,edx ; is this the last record
je LDNLastRec ; yes, then special case
cmp eax,ecx ; is this the first record
je LDNFirstRec ; yes, then special case
lds si,pNode ; get the node to delete
mov eax,[si+bx].dwNext ; eax has next
mov ecx,[si+bx].dwPrev ; ecx has prev
les di,[si+bx].dwPrev ; access previous record
lds si,[si+bx].dwNext ; access next record
mov es:[di+bx].dwNext,eax ; swap pointers
mov [si+bx].dwPrev,ecx
jmps LDNFreNode ; go free the node
LDNLastRec: cmp eax,ecx ; is the record the top
je LDNFinalRec ; yes, then is the last
les di,pNode ; get the node to delete
mov eax,es:[di+bx].dwPrev ; eax gets previous
les di,es:[di+bx].dwPrev ; access previous record
mov [si].hListEnd,eax ; reset the end of list
mov es:[di+bx].dwNext,eax ; next = itself for last
jmps LDNFreNode
LDNFirstRec:cmp eax,edx ; is the record the last
je LDNFinalRec ; yes, then is the last
les di,pNode ; get the node to delete
mov eax,es:[di+bx].dwNext ; eax gets previous
les di,es:[di+bx].dwNext ; access next record
mov [si].hListTop,eax ; reset top of list
mov es:[di+bx].dwPrev,eax ; prev = itself for top
jmps LDNFreNode
LDNFinalRec:mov dwptr [si].hListTop,0 ; only executed if
mov dwptr [si].hListEnd,0 ; final record is freed
LDNFreNode: lds si,hList ; access list header again
mov ax,[si].hListDS ; restore callers ds
mov ds,ax
cCall FARLOCALFREE <pNode> ; free the node
LDNExit:
cEnd
;------------------------------------------------------------------------------
; ListInsertNode - Inserts a Node in designated list before AtNode
;
; Returns : AX = NONZERO = success
;------------------------------------------------------------------------------
cProc ListInsertNode,<PUBLIC,FAR>,<ds,si,di>
parmD hList
parmD lpAtNode
parmD pNode
cBegin
mov ax, 0
cmp dwptr pNode,0 ; proof ptrs
je LINExit
cmp dwptr lpAtNode,0
je LINExit
lds si,hList ; access list header
mov bx,[si].wListSize ; get the record size
inc [si].dwListCount ; increment count
mov eax,lpAtNode ; get ptr to At Node
cmp eax,[si].hListTop ; is this the first record
mov eax,pNode ; get ptr to InsNode
je LINTopNode ; yes, handle differently
lds si,lpAtNode ; access at node
les di,[si+bx].dwPrev ; access prev node
mov eax,pNode ; get ptr to InsNode
push dwptr es:[di+bx].dwNext ; push prev/next pointer
mov es:[di+bx].dwNext,eax ; store the ptr to insnode
push dwptr [si+bx].dwPrev ; push at/prev pointer
mov [si+bx].dwPrev,eax ; our record is in
lds si, pNode
pop dwptr [si+bx].dwPrev ; pop the prev/next ptr
pop dwptr [si+bx].dwNext ; pop the at/prev ptr
mov ax,1 ; done
jmps LINExit
LINTopNode: les di,[si].hListTop ; es:di has TopNode
push dwptr [si].hListTop ; save the TopNode ptr
mov [si].hListTop,eax ; our record is new list top
lds si,pNode ; get our record
mov [si+bx].dwPrev,eax ; Top's Prev points to itself
pop [si+bx].dwNext ; Next is oldTop
mov es:[di+bx].dwPrev,eax ; OldTop's prev is our new
mov ax,1 ; Done
LINExit:
cEnd
;------------------------------------------------------------------------------
; ListFree - Frees a linked list
;
; Returns : Nothing
;------------------------------------------------------------------------------
cProc ListFree,<PUBLIC,FAR>,<ds,di,si>
parmD hList
cBegin
lds si, hList
LFLoop: cmp dwptr [si].hListTop, 0
je LFExit
cCall ListDeleteNode <hList, [si].hListTop>
jmps LFLoop
LFExit: mov ax,[si].hListDS
mov ds,ax
cCall FARLOCALFREE <hList>
cEnd
;------------------------------------------------------------------------------
; ListQSort - Sorts a linked list with a users compare routine
;
; Returns : Nothing
;
; 0. do minimal checks on arguments
; 1. check to see if array needs sorting
; 2. start QuickSort
;------------------------------------------------------------------------------
cProc ListQSort,<PUBLIC, FAR>,<ds,si,di>
parmD hList
parmD compare
cBegin
lds si, hList
mov ecx,[si].dwListCount
jecxz QsortDone ; ecx = 0 => list has no elements
dec ecx
jz QsortDone ; ecx = 0 => list has only 1 element
mov bx,[si].wListSize ; size of records in list
les di,[si].hListTop ; first record = es:di
; 1. check to see if array needs sorting
CheckLoop: push ecx ; see if array is already sorted
push bx ; save necessary registers
push es
push dwptr es:[di+bx].dwNext; pass the next pointer
push es
push di ; pass the current pointer
call dwptr compare ; call the users compare routine
pop es
pop bx
pop ecx
or ax,ax ; if ax is negative i.e. < 0 then
js Need2Sort ; do QuickSort
les di,es:[di+bx].dwNext ; get next node
loop CheckLoop
jmps QSortDone
Need2Sort: mov eax,compare
mov [si].lpCompare,eax
mov eax,1
cCall QuickSort <eax, [si].dwListCount>
QSortDone:
cEnd
;------------------------------------------------------------------------------
; Random - Generates a pseudorandom integer between Low and High
; Returns : EAX pseudorandom int
;------------------------------------------------------------------------------
cProc Random,<NEAR>,<ds>
parmD dwLow
parmD dwHigh
cBegin
push ecx
push edx
mov ax, SEG _DATA
mov ds,ax
mov eax,holdrand
mov ecx,214013
mul ecx
add eax,2531011
mov holdrand,eax
shr eax,16
and ax,7FFFh
mov ecx,dwHigh
sub ecx,dwLow
cdq
div ecx
add edx,dwLow
mov eax,edx
pop edx
pop ecx
cEnd
;------------------------------------------------------------------------------
; FastGetNode - Gets the nth record of a list
; NO Error Checking!!!
; DS:SI header
; BX List Size
; Returns : DX:AX Handle to the record
;------------------------------------------------------------------------------
cProc FastGetNode,<NEAR>,<ds,si>
parmD dwNode
cBegin
push ecx
mov ecx,dwNode
mov bx,[si].wListSize
lds si,[si].hListTop
dec ecx
jz FGNDone
FGNTop: lds si,[si+bx].dwNext
db 66h ; force LOOP on ECX
loop FGNTop
FGNDone: mov dx,ds
mov ax,si
pop ecx
cEnd
;------------------------------------------------------------------------------
; CallCompare - Calls the user supplied compare routine with pointers
;
; ON ENTRY : DS:SI List Header
; Returns : Nothing
;------------------------------------------------------------------------------
cProc CallCompare,<NEAR>,<es,ds,si,di>
parmD Record1
parmD Record2
cBegin
push edx
cCall FastGetNode <Record1>
push dx
push ax
cCall FastGetNode <Record2>
push dx
push ax
call dwptr [si].lpCompare
pop edx
cEnd
;------------------------------------------------------------------------------
; SwapNode - Swaps the two records associated with the indexes
;
; ON ENTRY : DS:SI List Header
; Returns : Nothing
;------------------------------------------------------------------------------
cProc SwapNode,<NEAR>,<es,ds,si,di>
parmD Record1
parmD Record2
cBegin
push eax
push edx
push ds ; hList
push si
cCall FastGetNode <Record1>
push dx ; lpRecord1
push ax
cCall FastGetNode <Record2>
push dx ; lpRecord2
push ax
cCall ListSwapNode
pop edx
pop eax
cEnd
;------------------------------------------------------------------------------
; QuickSort (Low, High)
;
; ON ENTRY: DS:SI List Header
;
; QuickSort works by picking a random "pivot" record in hList, then
; moving every record that is bigger to one side of the pivot, and every
; record that is smaller to the other side. QuickSort is then called
; recursively with the two subdivisions created by the pivot. Once the
; number of elements in a subdivision reaches two, the recursive calls end
; and the list is sorted.
;------------------------------------------------------------------------------
cProc QuickSort,<NEAR>,<eax>
parmD LowPtr
parmD HighPtr
cBegin
mov eax,HighPtr ; if (LowPtr < HighPtr)
cmp eax,LowPtr
jbe QSExit
sub eax,LowPtr ; if (HighPtr - LowPtr) = 1
cmp eax,1
jne else1
; Only two elements in this subdivision swap them if they are out
; order, then end recursive calls
cCall CallCompare <LowPtr, HighPtr>
cmp ax,1
jne QSExit
; (if [LowPtr] > [HighPtr])
; swap(LowPtr, HighPtr)
cCall SwapNode <LowPtr, HighPtr>
jmp QSExit
else1: ; ELSE
; Pick a pivot record, then move it to the end:
cCall Random <LowPtr, HighPtr>
cCall SwapNode <eax, HighPtr>
do1: ; DO
; Move in from both sides towards the pivot element:
mov eax,LowPtr ; I = LowPtr
mov edx,HighPtr ; J = HighPtr
do2: cmp eax,edx ; DO WHILE (I < J)
jge enddo2
push eax ; AND ([I] <= [pivot])
cCall CallCompare <eax, HighPtr>
cmp ax,1
pop eax
je enddo2
inc eax ; I = I + 1
jmps do2
enddo2:
do3: cmp edx,eax ; DO WHILE (J > I)
jbe enddo3
push eax ; AND ([J] >= [pivot])
cCall CallCompare <edx, HighPtr>
cmp ax,-1
pop eax
je enddo3
dec edx ; J = J - 1
jmps do3
enddo3:
; If we haven't reached the pivot element, it means that two
; elements on either side are out of order, so swap them:
cmp eax,edx ; IF I < J
jge enddo1
cCall SwapNode <eax, edx>
enddo1: cmp eax,edx
jb do1 ; LOOP WHILE I < J
; Move the pivot element back to its proper place in the array:
cCall SwapNode <eax, HighPtr>
; Recursively call QuickSort
push eax
push dwptr LowPtr
dec eax
push eax
call QuickSort ; QuickSort (LowPtr, I - 1)
pop eax
push eax
inc eax
push eax
push dwptr HighPtr
call QuickSort ; QuickSort (I + 1, HighPtr)
pop eax
QSExit:
cEnd
sEnd CODE
END