home *** CD-ROM | disk | FTP | other *** search
- 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
-
-
-