; =============================================================================
;
; Litos - List
;
; =============================================================================
CODE_SECTION 32
; ------------- Macro - initialized list head (or initialized safe list entry)
%define LISTHEAD dd $,$
; ------------- Macro - initialized linked list entry
; %1 = pointer to next entry, %2 = pointer to previous entry
%macro LINKEDLIST 2
dd %1,%2
%endmacro
; ------------- Macro - initialize list head (%1 = pointer to list head)
%macro LISTINIT 1
mov [%1+LIST_Next],%1 ; next (first) entry in chain
mov [%1+LIST_Prev],%1 ; previous (last) entry in chain
%endmacro
; ------------- Macro - link two entries together (%1=1st entry, %2=2nd entry)
%macro LINKLINK 2
mov [%1+LIST_Next],%2 ; link second entry after first one
mov [%2+LIST_Prev],%1 ; link first entry previous second
%endmacro
; ------------- Macro - add new entry into begin of list or after current entry
; %1 = list head or current entry, %2 = new entry, %3 = temporary register
%macro LISTADD 3
mov %3,[%1+LIST_Next] ; get next (first) entry
LINKLINK %1,%2 ; link head/current with new entry
LINKLINK %2,%3 ; link new entry with next entry
%endmacro
; ------------- Macro - add new entry into end of list or before current entry
; %1 = list head or current entry, %2 = new entry, %3 = temporary register
%macro LISTLAST 3
mov %3,[%1+LIST_Prev] ; get previous (last) entry
LINKLINK %3,%2 ; link new entry with previous entry
LINKLINK %2,%1 ; link head/current with new entry
%endmacro
; ------------- Macro - delete (detach) entry from the list
; %1 = entry to delete, %2 and %3 = temporary registers
; %1 and %3 can be the same, in that case content of %1 will be changed
; On output: %2 = old previous entry, %3 = old next entry
%macro LISTDEL 3
mov %2,[%1+LIST_Prev] ; get previous entry
mov %3,[%1+LIST_Next] ; get next entry
LINKLINK %2,%3 ; link previous entry with next entry
%endmacro
; ------------- Macro - detach entry from the previous entry
; %1 = entry to delete, %2 = previous entry, %3 = temporary registers
%macro LISTDELPREV 3
mov %3,[%1+LIST_Next] ; get next entry
LINKLINK %2,%3 ; link previous entry with next entry
%endmacro
; ------------- Macro - test if list is empty (output: ZY = list is empty)
; %1 = pointer to list head
%macro LISTTEST 1
cmp [%1+LIST_Next],%1 ; check if list is empty
%endmacro
; ------------- Macro - mark safe list entry as empty (%1 = safe list entry)
%macro LISTEMPTY 1
mov [%1+LIST_Next],%1 ; mark safe list entry as empty
%endmacro
; -----------------------------------------------------------------------------
; Initialize list head
; -----------------------------------------------------------------------------
; INPUT: EBX = list head
; -----------------------------------------------------------------------------
ListInit: LISTINIT ebx ; initialize list head
ret
; -----------------------------------------------------------------------------
; Initialize safe list entry
; -----------------------------------------------------------------------------
; INPUT: EBX = safe list entry
; NOTES: Safe list entry is not in list if NEXT points to itself.
; -----------------------------------------------------------------------------
ListSafeInit: LISTEMPTY ebx ; initialize safe list entry
ret
; -----------------------------------------------------------------------------
; Add new entry into begin of list or after current entry
; -----------------------------------------------------------------------------
; INPUT: EAX = new entry
; EBX = list head or current entry
; -----------------------------------------------------------------------------
ListAfter:
ListAdd: push ecx ; push ECX
LISTADD ebx,eax,ecx ; add new entry into list
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Add new safe entry into begin of list or after current entry
; -----------------------------------------------------------------------------
; INPUT: EAX = new entry
; EBX = list head or current entry
; NOTES: Safe list entry is not in list if NEXT points to itself.
; -----------------------------------------------------------------------------
ListSafeAfter:
ListSafeAdd: LISTTEST eax ; test if list entry is in a list
jne ListSafeAdd4 ; list entry is already in a list
push ecx ; push ECX
LISTADD ebx,eax,ecx ; add new entry into list
pop ecx ; pop ECX
ListSafeAdd4: ret
; -----------------------------------------------------------------------------
; Add new entry into end of list or before current entry
; -----------------------------------------------------------------------------
; INPUT: EAX = new entry
; EBX = list head or current entry
; -----------------------------------------------------------------------------
ListBefore:
ListLast: push ecx ; push ECX
LISTLAST ebx,eax,ecx ; add new entry into list
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Add new safe entry into end of list or before current entry
; -----------------------------------------------------------------------------
; INPUT: EAX = new safe entry
; EBX = list head or current entry
; NOTES: Safe list entry is not in list if NEXT points to itself.
; -----------------------------------------------------------------------------
ListSafeBefore:
ListSafeLast: LISTTEST eax ; test if list entry is in a list
jne ListSafeLast4 ; list entry is already in a list
push ecx ; push ECX
LISTLAST ebx,eax,ecx ; add new entry into list
pop ecx ; pop ECX
ListSafeLast4: ret
; -----------------------------------------------------------------------------
; Delete (detach) list entry from the list
; -----------------------------------------------------------------------------
; INPUT: EAX = entry to delete
; -----------------------------------------------------------------------------
ListDel: push ebx ; push EBX
push ecx ; push ECX
LISTDEL eax,ebx,ecx ; delete list entry
pop ecx ; pop ECX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Delete (detach) safe list entry from the list
; -----------------------------------------------------------------------------
; INPUT: EAX = safe entry to delete
; NOTES: Safe list entry is not in list if NEXT points to itself.
; -----------------------------------------------------------------------------
ListSafeDel: LISTTEST eax ; test if list entry is in a list
je ListSafeDel4 ; list entry is not in a list
push ebx ; push EBX
push ecx ; push ECX
LISTDEL eax,ebx,ecx ; delete list entry
pop ecx ; pop ECX
pop ebx ; pop EBX
LISTEMPTY eax ; mark entry as empty
ListSafeDel4: ret
; -----------------------------------------------------------------------------
; Delete (detach) list entry from the list
; -----------------------------------------------------------------------------
; INPUT: EBX = entry to delete
; -----------------------------------------------------------------------------
ListDelEBX: push eax ; push EAX
push ecx ; push ECX
LISTDEL ebx,eax,ecx ; delete list entry
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Delete (detach) list entry from the list (using EDX registry)
; -----------------------------------------------------------------------------
; INPUT: EDX = entry to delete
; -----------------------------------------------------------------------------
ListDelEDX: push ebx ; push EBX
push ecx ; push ECX
LISTDEL edx,ebx,ecx ; delete list entry
pop ecx ; pop ECX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Replace old entry with new one
; -----------------------------------------------------------------------------
; INPUT: EAX = new entry
; EBX = old entry
; -----------------------------------------------------------------------------
; ------------- Push registers
ListXchg: push ecx ; push ECX
push edx ; push EDX
; ------------- Exchange entries
mov ecx,[ebx+LIST_Prev] ; ECX <- get previous entry
mov edx,[ebx+LIST_Next] ; EDX <- get next entry
mov [eax+LIST_Prev],ecx ; link previous entry to new one
mov [eax+LIST_Next],edx ; link next entry to new one
mov [ecx+LIST_Next],eax ; link new entry to previous one
mov [edx+LIST_Prev],eax ; link new entry to next one
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Detach list chain and splice it with other list
; -----------------------------------------------------------------------------
; INPUT: EAX = source list head (it will become empty)
; EBX = destination list head
; -----------------------------------------------------------------------------
; ------------- Push registers
ListSplice: push ecx ; push ECX
push edx ; push EDX
push esi ; push ESI
; ------------- Check if source list is already empty
cmp eax,[eax+LIST_Next] ; is source list empty?
je ListSplice2 ; source list is empty
; ------------- Detach list chain from source list
mov ecx,[eax+LIST_Next] ; ECX <- first entry of source list
mov edx,[eax+LIST_Prev] ; EDX <- last entry of source list
mov [eax+LIST_Next],eax ; close source list (first entry)
mov [eax+LIST_Prev],eax ; close source list (last entry)
; ------------- Atach list chain to destination list
mov esi,[ebx+LIST_Next] ; ESI <- first entry of destination
mov [ebx+LIST_Next],ecx ; link first entry to destination
mov [ecx+LIST_Prev],ebx ; link destination to first entry
mov [edx+LIST_Next],esi ; link 1st entry 2 to last entry 1
mov [esi+LIST_Prev],edx ; link last entry 1 to 1st entry 2
; ------------- Pop registers
ListSplice2: pop esi ; pop ESI
pop edx ; pop EDX
pop ecx ; pop ECX
ret
|