MAX_CCITEMS = 100
uglobal
hCCList dd 0
hCCPrefix dd 0
endg
idCCList = 763
proc CreateCCList, .parent
begin
push ebx
invoke CreateWindowExA, WS_EX_CLIENTEDGE, cFormClassName, 0, WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN, \
0, 0, 300, 120, 0, 0, [hInstance], 0
mov [hCCList], eax
invoke SetWindowLongA, [hCCList], GWL_HWNDPARENT, [.parent]
stdcall SubclassWindow, [hCCList], CCParentProc
invoke CreateWindowExA, 0, cListboxClassName, 0, \
WS_CHILD or WS_VSCROLL or WS_VISIBLE or LBS_NOINTEGRALHEIGHT or LBS_OWNERDRAWFIXED or LBS_NODATA, \
0, 0, 300, 120, [hCCList], idCCList, [hInstance], 0
mov ebx, eax
stdcall SubclassWindow, ebx, CCListProc
stdcall SetAlign, ebx, waClient
invoke GetStockObject, DEFAULT_GUI_FONT
invoke SendMessageA, ebx, WM_SETFONT, eax, TRUE
mov [hCCPrefix], 0
pop ebx
return
endp
; returns pointer to the string in ebx
proc GetCCListSelected
begin
push eax ecx edx
invoke SendMessageA, [hCCList], LB_GETCURSEL, 0, 0
add eax, 1
jc .err
mov ebx, eax
invoke GetWindowLongA, [hCCList], GWL_USERDATA
cmp [eax+TArray.count], ebx
jb .err
mov ebx, [eax+TArray.array+4*ebx-4]
mov ebx, [ebx+TLabel.iName]
add ebx, [ptrNames]
clc
.err:
pop edx ecx eax
return
endp
proc ClearCCList
begin
invoke SendMessageA, [hCCList], LB_SETCOUNT, 0, 0
invoke GetWindowLongA, [hCCList], GWL_USERDATA
stdcall FreeMem, eax
stdcall CreateArray, 4 ; dword array.
invoke SetWindowLongA, [hCCList], GWL_USERDATA, eax
return
endp
proc SelectCCList, .hStr
begin
push ebx esi edi
stdcall StrPtr, [.hStr]
mov edi, eax
invoke GetWindowLongA, [hCCList], GWL_USERDATA
mov ebx, [eax+TArray.count]
lea esi, [eax+TArray.array]
or eax, -1
.matchloop:
inc eax
cmp eax, ebx
je .notfound
mov ecx, [esi]
lea esi, [esi+4]
mov ecx, [ecx+TLabel.iName]
add ecx, [ptrNames]
stdcall StringMatch, ecx, edi
jnc .matchloop
invoke SendMessageA, [hCCList], LB_SETCURSEL, eax, 0
clc
return
.notfound:
invoke SendMessageA, [hCCList], LB_SETCURSEL, 0, 0
stc
return
endp
winproc CCParentProc
begin
cmp ebx, WM_KEYDOWN
je .relay
cmp ebx, LB_ADDSTRING
jl .process
cmp ebx, LB_ITEMFROMPOINT
ja .process
.relay:
invoke SendDlgItemMessageA, [.hwnd], idCCList, [.wmsg], [.wparam], [.lparam]
clc
return
.process:
ondefault
stc
return
onmessage AM_INITWINDOW
stdcall CreateArray, 4 ; dword array.
invoke SetWindowLongA, [.hwnd], GWL_USERDATA, eax
clc
return
onmessage WM_SIZE
invoke GetDlgItem, [.hwnd], idCCList
invoke InvalidateRect, eax, 0, 0
xor eax, eax
clc
return
onmessage WM_CLOSE
invoke GetWindowLongA, [.hwnd], GWL_HWNDPARENT
invoke SetFocus, eax
invoke DestroyWindow, [.hwnd]
xor eax, eax
mov [hCCList], eax
clc
return
onmessage WM_DESTROY
invoke GetWindowLongA, [.hwnd], GWL_USERDATA
stdcall FreeMem, eax
stc
return
onmessage WM_MEASUREITEM
locals
.ccrect RECT
endl
mov esi, [.lparam]
cmp [esi+MEASUREITEMSTRUCT.CtlType], ODT_LISTBOX
jne .ondefault
cmp [esi+MEASUREITEMSTRUCT.CtlID], idCCList
jne .ondefault
invoke GetDlgItem, [.hwnd], idCCList
mov ebx, eax
lea ecx, [.ccrect]
invoke GetClientRect, ebx, ecx
push [.ccrect.right]
pop [esi+MEASUREITEMSTRUCT.itemWidth]
or eax, -1
clc
return
onmessage WM_DRAWITEM
locals
.rectL RECT
.rectR RECT
.bkbrush dd ?
.buffer rb 32
endl
cmp [.wparam], idCCList
jne .ondefault
mov esi, [.lparam]
mov eax, [esi+DRAWITEMSTRUCT.hwndItem]
mov eax, COLOR_HIGHLIGHT
mov ebx, COLOR_HIGHLIGHTTEXT
test [esi+DRAWITEMSTRUCT.itemState], ODS_SELECTED or ODS_FOCUS
jnz @f
mov eax, COLOR_WINDOW
mov ebx, COLOR_WINDOWTEXT
@@:
invoke GetSysColor, eax
invoke CreateSolidBrush, eax
mov [.bkbrush], eax
invoke GetSysColor, ebx
invoke SetTextColor, [esi+DRAWITEMSTRUCT.hDC], eax
invoke SetBkMode, [esi+DRAWITEMSTRUCT.hDC], TRANSPARENT
; First fill the background
lea eax, [esi+DRAWITEMSTRUCT.rcItem]
invoke FillRect, [esi+DRAWITEMSTRUCT.hDC], eax, [.bkbrush]
; then compute the rectangles
mov eax, [esi+DRAWITEMSTRUCT.rcItem.left]
mov ecx, [esi+DRAWITEMSTRUCT.rcItem.right]
mov [.rectL.left], eax
mov [.rectL.right], ecx
mov [.rectR.left], ecx
mov [.rectR.right], ecx
sub ecx, eax
shr ecx, 2 ; 1/4 of the field for the value.
sub [.rectL.right], ecx
sub [.rectR.left], ecx
mov eax, [esi+DRAWITEMSTRUCT.rcItem.top]
mov ecx, [esi+DRAWITEMSTRUCT.rcItem.bottom]
mov [.rectL.top], eax
mov [.rectL.bottom], ecx
mov [.rectR.top], eax
mov [.rectR.bottom], ecx
add [.rectL.left], 4
add [.rectR.left], 4
invoke GetSysColor, COLOR_BTNFACE
invoke CreatePen, PS_SOLID, 0, eax
invoke SelectObject, [esi+DRAWITEMSTRUCT.hDC], eax
push eax
invoke MoveToEx, [esi+DRAWITEMSTRUCT.hDC], [.rectL.right], [.rectL.top], NULL
invoke LineTo, [esi+DRAWITEMSTRUCT.hDC], [.rectL.right], [.rectL.bottom]
mov edi, [.rectL.bottom]
dec edi
invoke MoveToEx, [esi+DRAWITEMSTRUCT.hDC], [esi+DRAWITEMSTRUCT.rcItem.left], edi, NULL
invoke LineTo, [esi+DRAWITEMSTRUCT.hDC], [.rectR.right], edi
invoke SelectObject, [esi+DRAWITEMSTRUCT.hDC] ; from the stack
invoke DeleteObject, eax
; then write the text
mov edi, [esi+DRAWITEMSTRUCT.itemID]
cmp edi, -1
je .cleanup
invoke GetWindowLongA, [.hwnd], GWL_USERDATA
cmp edi, [eax+TArray.count]
jae .cleanup
mov edi, [eax+TArray.array + 4*edi]
mov eax, [edi+TLabel.iName]
add eax, [ptrNames]
lea ecx, [.rectL]
invoke DrawTextA, [esi+DRAWITEMSTRUCT.hDC], eax, -1, ecx, DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_END_ELLIPSIS
cNotDefined text 'undefined'
cVirtual text 'virtual'
; then write the value
test [edi+TLabel.flags], lfDefined
jz .notdefined
cmp [edi+TLabel.SIBEx], 0
jne .virtual
stdcall NumToStr, [edi+TLabel.ValueLo], ntsHex or ntsSigned
jmp .printvalue
.notdefined:
stdcall StrDup, cNotDefined
jmp .printvalue
.virtual:
stdcall StrDup, cVirtual
.printvalue:
push eax
stdcall StrPtr, eax
lea ecx, [.rectR]
invoke DrawTextA, [esi+DRAWITEMSTRUCT.hDC], eax, -1, ecx, DT_SINGLELINE or DT_LEFT or DT_VCENTER
stdcall StrDel ; from the stack.
.cleanup:
invoke DeleteObject, [.bkbrush]
or eax, -1
clc
return
endwp
winproc CCListProc
begin
ondefault
stc
return
; This makes CCList to never get the focus.
;onmessage WM_SETFOCUS
; invoke GetParent, [.hwnd]
; invoke SetFocus, eax
; xor eax, eax
; clc
; return
;-----------------------------------------------------------------------
onmessage WM_LBUTTONDBLCLK
invoke SendMessageA, [hEditorsHost], EHM_GETCURRENTASMEDIT, 0, 0
invoke PostMessageA, eax, WM_KEYDOWN, VK_RETURN, 0
clc
return
;-----------------------------------------------------------------------
onmessage WM_KEYDOWN
mov ebx, [.wparam]
call JumpTo
MessageList \
VK_DOWN, .ondefault, \
VK_UP, .ondefault, \
VK_PRIOR, .ondefault, \
VK_NEXT, .ondefault, \
VK_HOME, .ondefault, \
VK_END, .ondefault
; invoke SendMessageA, [hEditorsHost], EHM_GETCURRENTASMEDIT, 0, 0
invoke GetParent, [.hwnd]
invoke GetWindowLongA, eax, GWL_HWNDPARENT
invoke PostMessageA, eax, [.wmsg], [.wparam], [.lparam]
xor eax, eax
clc
return
endwp
proc UpdateCCPosition
.aepos AEPOS
.caret AECARETXY
.rect RECT
.workrect RECT
.prefix rb $100
.word rb $100
.aedit dd ?
; benchmark variables
; .time dd ?
; .count dd ?
begin
cmp [hCCList], 0
je .finish
stdcall WaitForCompiler
jc .finish
invoke GetWindowLongA, [hCCList], GWL_HWNDPARENT
mov [.aedit], eax
lea eax, [.aepos]
invoke SendMessageA, [.aedit], AEM_GETPOS, eax, 0
lea ebx, [.caret]
invoke SendMessageA, [.aedit], AEM_GETCARETXY, ebx, 0
invoke ClientToScreen, [.aedit], ebx
add ebx, 8
invoke ClientToScreen, [.aedit], ebx
sub ebx, 8
lea eax, [.rect]
invoke GetWindowRect, [hCCList], eax
mov eax, [.rect.right]
mov ecx, [.rect.bottom]
sub eax, [.rect.left]
sub ecx, [.rect.top]
mov [.rect.right], eax
mov [.rect.bottom], ecx
lea ebx, [.workrect]
invoke SystemParametersInfoA, SPI_GETWORKAREA,0,ebx,0
mov eax, [.workrect.right]
sub eax, [.rect.right]
mov ecx, [.caret.x0]
cmp eax, ecx
jle @f
mov eax, ecx
@@:
mov edx, [.workrect.bottom]
sub edx, [.rect.bottom]
mov ecx, [.caret.y1]
add ecx, 1
cmp edx, ecx
jg @f
mov ecx, [.caret.y0]
sub ecx, [.rect.bottom]
sub ecx, 2
@@:
invoke SetWindowPos, [hCCList], NULL, eax, ecx, 0, 0, SWP_NOSIZE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOCOPYBITS
lea ebx, [.word]
invoke SendMessageA, [.aedit], AEM_GETWORDATCARET, $100, ebx
cmp byte [.word], '.'
jne .localok
cmp [hCCPrefix], 0
jne .prefixok
stdcall SearchForLabelPrefix, [.aedit], [.aepos.caretLine]
mov [hCCPrefix], eax
.prefixok:
cmp [hCCPrefix], 0
je .localok
stdcall StrLen, [hCCPrefix]
mov ecx, eax
jecxz .localok ; the prefix was not found or there is no prefix.
stdcall StrPtr, [hCCPrefix]
lea esi, [eax+ecx] ; the end of the string
.copy_prefix:
dec esi
mov al, [esi]
dec ebx
mov [ebx], al
loop .copy_prefix
; here ebx contains a pointer to the whole name including the parent label.
.localok:
stdcall ClearCCList
stdcall SearchTree, ebx, ptrLabels
test eax, eax
jz .destroycc
mov esi, [eax]
test esi, esi
jz .destroycc
mov ebx, [esi+TArray.count]
lea esi, [esi+TArray.array]
test ebx, ebx
jz .destroycc
mov edi, edx ; The last word
invoke GetWindowLongA, [hCCList], GWL_USERDATA
mov edx, eax
test edx, edx
jz .destroycc
xor ecx, ecx
; benchmark code.
; mov [.count], ecx
; stdcall GetTimestamp
; mov [.time], eax
.fill_loop:
; inc [.count] ; benchmark
mov eax, [esi+TLabel.iName]
test eax, eax
jz .next
add eax, [ptrNames]
stdcall StringMatch, eax, edi
jnc .next
stdcall AddArrayItems, edx, 1
mov [eax], esi
inc ecx
cmp ecx, MAX_CCITEMS
jae .end_fill_loop
.next:
add esi, sizeof.TLabel
dec ebx
jnz .fill_loop
.end_fill_loop:
; benchmark code...
; pushad
; stdcall GetTimestamp
; sub eax, [.time]
; stdcall Output, 'Fill loop time:'
; stdcall OutputNumber, eax, 10, 8
; stdcall Output, <' ms ', 13, 10>
;
; stdcall Output, 'Total processed:'
; stdcall OutputNumber, [.count], 10, 8
; stdcall Output, <' records ', 13, 10>
;
; popad
push ecx
invoke SetWindowLongA, [hCCList], GWL_USERDATA, edx
pop ecx
test ecx, ecx
jz .destroycc
invoke SendMessageA, [hCCList], LB_SETCOUNT, ecx
stdcall SelectCCList, edi
stdcall StrDel, edi
invoke SetWindowPos, [hCCList], NULL, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_SHOWWINDOW or SWP_NOACTIVATE
.finish:
return
.destroycc:
invoke PostMessageA, [hCCList], WM_CLOSE, 0, 0
return
endp
; If str1 begins with str2 then returns CF=1
; else CF=0
; preserves all registers.
proc StringMatch, .str1, .str2
begin
push esi edi eax
mov esi, [.str1]
mov edi, [.str2]
.loop:
mov al, [edi]
lea edi, [edi+1]
test al,al
jz .match
mov ah, [esi]
lea esi, [esi+1]
test ah,ah
jz .notmatch
or eax, $2020
cmp al,ah
je .loop
.notmatch:
clc
pop eax edi esi
return
.match:
stc
pop eax edi esi
return
endp
; searches the preprocessed source for the last global label definition before the
; specified line in the file. Returns the name of this label as a string in eax.
; If such label is not found, returns eax=0
proc SearchForLabelPrefix, .editor, .caretY
begin
push edx esi
stdcall GetEditorFile, [.editor]
stdcall SearchFileInGlobalIndex, [eax+TOpenFile.hFileName]
jc .not_found
mov esi, eax ; pointer to TArray of strinigs for needed file.
mov edx, [.caretY]
dec edx
cmp edx, [esi+TArray.count]
jb .lineok
mov edx, [esi+TArray.count]
dec edx
.lineok:
mov eax, [esi+TArray.array+4*edx] ; handle to the global label name
test eax, eax
jz .not_found
pop esi edx
clc
return
.not_found:
pop esi edx
stc
return
endp
struct TGlobalIndexItem
.iFilename dd ?
.ptrLines dd ?
ends
proc FreeGlobalIndex
begin
push eax ecx esi
mov esi, [ptrGlobalsList]
test esi, esi
jz .finish
mov ecx, [esi+TArray.count]
.loop:
dec ecx
js .end_free
mov eax, [esi+TArray.array + sizeof.TGlobalIndexItem * ecx + TGlobalIndexItem.ptrLines]
test eax, eax
jz .loop
stdcall FreeMem, eax
jmp .loop
.end_free:
stdcall ListFree, [esi+TArray.lparam], StrDel
stdcall FreeMem, esi
mov [ptrGlobalsList], 0
.finish:
pop esi ecx eax
return
endp
proc CreateGlobalIndex
.end dd ?
.current dd ? ; handle of string with the current root label.
.fLabel dd ?
.fSkip dd ?
begin
pushad
stdcall FreeGlobalIndex
mov [.current], 0
stdcall CreateArray, sizeof.TGlobalIndexItem
mov [ptrGlobalsList], eax
mov esi, eax
stdcall CreateArray, 4
mov [esi+TArray.lparam], eax ; array with all defined strings for later free.
mov esi, [ptrPreprocessed]
mov eax, [lenPreprocessed]
add eax, esi
mov [.end], eax
test esi, esi
jz .finish
; start of a preprocessor line...
.line_loop:
cmp esi, [.end]
jae .end_of_file
test [esi+TIntLine.LineNumber], $80000000
jnz .process_line ; this line is generated by macro and thus is nor in the source.
stdcall SearchInGIndex, [ptrGlobalsList], [esi+TIntLine.ofsGenerator]
jnc .fileok
stdcall AddArrayItems, [ptrGlobalsList], 1
mov [ptrGlobalsList], edx
.fileok:
mov edi, eax
mov eax, [esi+TIntLine.ofsGenerator]
mov [edi+TGlobalIndexItem.iFilename], eax
mov eax,[edi+TGlobalIndexItem.ptrLines]
test eax, eax
jnz .linesok
stdcall CreateArray, 4
mov [edi+TGlobalIndexItem.ptrLines], eax
.linesok:
mov edx, eax
mov eax, [esi+TIntLine.LineNumber]
sub eax, [edx+TArray.count]
jb .this_line_ok
stdcall AddArrayItems, edx, eax
mov [edi+TGlobalIndexItem.ptrLines], edx
.this_line_ok:
mov eax, [esi+TIntLine.LineNumber]
dec eax
lea edi, [edx+TArray.array+4*eax] ; pointer to the memory for the global label string.
.process_line:
add esi, sizeof.TIntLine
mov [.fLabel], 0
mov [.fSkip], 0
.pre_loop:
lodsb
cmp al, $1a
je .symbol
cmp al, $22
je .string
cmp al, $3b
je .preprocessor
test al, al
jnz .pre_loop
; line end...
mov eax, [.current]
mov [edi], eax
jmp .line_loop
.preprocessor:
mov [.fSkip], 1
.symbol:
movzx eax, byte [esi]
lea esi, [esi+1]
mov ebx, esi
add esi, eax
cmp [.fSkip], 0
jne .pre_loop
cmp [.fLabel], 0
jne .label_name
cmp byte [esi], ':' ; this symbol is label, so check it.
je .label_name
call .check_for_dd
jc .label_name
cmp eax, 5
jne .pre_loop
mov eax, [ebx]
or eax, $20202020
cmp eax, 'labe'
jne .pre_loop
mov al, [ebx+4]
or al, $20
cmp al, 'l'
jne .pre_loop
mov [.fLabel], 1
jmp .pre_loop
.label_name:
cmp byte [ebx], '.' ; it is local label
je .pre_loop
cmp word [ebx], '@@'
je .pre_loop
mov ecx, eax
stdcall StrNew
mov [.current], eax
stdcall StrCopyPart, eax, ebx, 0, ecx
; save the string in one place for later free.
push eax
mov ecx, [ptrGlobalsList]
stdcall AddArrayItems, [ecx+TArray.lparam], 1
mov [ecx+TArray.lparam], edx
pop dword [eax]
mov [.fLabel], 0
mov [.fSkip], 1
jmp .pre_loop
.string:
lodsd
add esi, eax
jmp .pre_loop
; check for data definition directive
.check_for_dd:
push eax
cmp byte [esi], $1a
jne .no_dd
mov eax, [esi+2]
or eax, $20202020
cmp byte [esi+1], 4
jne .no_file
cmp eax, 'file'
jne .no_dd
.yes_dd:
pop eax
stc
retn
.no_file:
cmp byte [esi+1], 2
jne .no_dd
cmp ax, 'rb'
je .yes_dd
cmp ax, 'rw'
je .yes_dd
cmp ax, 'rd'
je .yes_dd
cmp ax, 'rp'
je .yes_dd
cmp ax, 'rf'
je .yes_dd
cmp ax, 'rq'
je .yes_dd
cmp ax, 'rt'
je .yes_dd
cmp ax, 'db'
je .yes_dd
cmp ax, 'dw'
je .yes_dd
cmp ax, 'du'
je .yes_dd
cmp ax, 'dd'
je .yes_dd
cmp ax, 'dp'
je .yes_dd
cmp ax, 'df'
je .yes_dd
cmp ax, 'dq'
je .yes_dd
cmp ax, 'dt'
je .yes_dd
.no_dd:
pop eax
clc
retn
.end_of_file:
.finish:
popad
return
endp
proc SearchInGIndex, .ptrGIndex, .value
begin
push ecx esi
mov esi, [.ptrGIndex]
mov ecx, [esi+TArray.count]
.loop:
dec ecx
js .not_found
mov eax, [esi+TArray.array+sizeof.TGlobalIndexItem*ecx+TGlobalIndexItem.iFilename]
cmp eax, [.value]
jne .loop
.found:
lea eax, [esi+TArray.array+sizeof.TGlobalIndexItem*ecx]
pop esi ecx
return
.not_found:
stc
pop esi ecx
return
endp
proc SearchFileInGlobalIndex, .hFilename
begin
push ecx esi
mov esi, [ptrGlobalsList]
test esi, esi
jz .not_found
mov ecx, [esi+TArray.count]
.loop:
dec ecx
js .not_found
mov eax, [esi+TArray.array+sizeof.TGlobalIndexItem*ecx+TGlobalIndexItem.iFilename]
test eax, eax
jnz .fileok
mov eax, [ptrMainFilename]
jmp .compare
.fileok:
add eax, [ptrPreprocessed]
.compare:
stdcall StrCompFilename, eax, [.hFilename]
jnc .loop
; equal files
mov eax, [esi+TArray.array+sizeof.TGlobalIndexItem*ecx+TGlobalIndexItem.ptrLines]
test eax, eax
jz .not_found
clc
pop esi ecx
return
.not_found:
xor eax, eax
stc
pop esi ecx
return
endp
proc StrCompFilename, .hName1, .hName2
.file1 rb 1024
.file2 rb 1024
.name dd ?
begin
pushad
lea esi, [.file1]
lea edi, [.file2]
stdcall StrPtr, [.hName1]
lea edx, [.name]
invoke GetFullPathNameA, eax, 1024, esi, edx
cmp eax, 1023
ja .not_equal
test eax, eax
jz .not_equal
mov ebx, eax
stdcall StrPtr, [.hName2]
lea edx, [.name]
invoke GetFullPathNameA, eax, 1024, edi, edx
cmp eax, 1023
ja .not_equal
test eax, eax
jz .not_equal
cmp eax, ebx
jne .not_equal
mov ecx, ebx
jecxz .equal
.loop:
mov al, [esi]
mov ah, [edi]
lea esi, [esi+1]
lea edi, [edi+1]
; cmp al, '\'
; jne @f
; mov al, '/'
;
;@@:
; cmp ah, '\'
; jne @f
; mov ah, '/'
;@@:
cmp al, $41
jb @f
cmp al, $5f
ja @f
add al, $20
@@:
cmp ah, $41
jb @f
cmp ah, $5f
ja @f
add ah, $20
@@:
cmp al, ah
jne .not_equal
loop .loop
.equal:
stc
popad
return
.not_equal:
clc
popad
return
endp