
MAX_CCITEMS = 100


uglobal
  hCCList         dd 0
  hCCPrefix       dd 0
endg

idCCList = 763


proc CreateCCList, .parent
begin
        push    ebx

        invoke  CreateWindowExW, WS_EX_CLIENTEDGE, cFormClassName, 0, WS_POPUP,   \
                                0, 0, 300, 120, [.parent], 0, [hInstance], 0
        mov     [hCCList], eax

        invoke  SetPropW, eax, [propOwnerAsmEdit], [.parent]
;        invoke  SetWindowLongA, [hCCList], GWL_HWNDPARENT, [.parent]
        stdcall SubclassWindow, [hCCList], CCParentProc

        invoke  CreateWindowExW, 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 GetDefaultFont, gdfMessage
        invoke  SendMessageW, 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  SendMessageW, [hCCList], LB_GETCURSEL, 0, 0
        add     eax, 1
        jc      .err

        mov     ebx, eax

        invoke  GetWindowLongW, [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  SendMessageW, [hCCList], LB_SETCOUNT, 0, 0

        invoke  GetWindowLongW, [hCCList], GWL_USERDATA

        stdcall FreeMem, eax
        stdcall CreateArray, 4  ; dword array.

        invoke  SetWindowLongW, [hCCList], GWL_USERDATA, eax
        return
endp




proc SelectCCList, .hStr
begin
        push    ebx esi edi

        stdcall StrPtr, [.hStr]
        mov     edi, eax

        invoke  GetWindowLongW, [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, FALSE

        jnc     .matchloop

        invoke  SendMessageW, [hCCList], LB_SETCURSEL, eax, 0
        clc
        return

.notfound:
        invoke  SendMessageW, [hCCList], LB_SETCURSEL, -1, 0
        stc
        return
endp






proc CCParentProc, .hwnd, .wmsg, .wparam, .lparam
begin
        cmp     ebx, WM_KEYDOWN
        je      .relay

        cmp     ebx, LB_ADDSTRING
        jl      .process
        cmp     ebx, LB_ITEMFROMPOINT
        ja      .process

.relay:
        invoke  SendDlgItemMessageW, [.hwnd], idCCList, [.wmsg], [.wparam], [.lparam]
        clc
        return

.process:

        dispatch ebx

.ondefault:
        stc
        return

oncase WM_SETFOCUS
        xor     eax, eax
        clc
        return

oncase AM_INITWINDOW
        stdcall CreateArray, 4  ; dword array.
        invoke  SetWindowLongW, [.hwnd], GWL_USERDATA, eax
        clc
        return


oncase WM_SIZE
        invoke  GetDlgItem, [.hwnd], idCCList
        invoke  InvalidateRect, eax, 0, 0
        xor     eax, eax
        clc
        return


oncase WM_CLOSE
        invoke  DestroyWindow, [.hwnd]
        xor     eax, eax
        mov     [hCCList], eax
        clc
        return


oncase WM_DESTROY
        invoke  GetWindowLongW, [.hwnd], GWL_USERDATA
        stdcall FreeMem, eax
        stc
        return



oncase 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


oncase 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, 1          ; 1/2 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  GetWindowLongW, [.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]

        stdcall utf8ToWideChar, eax
        push    eax

        lea     ecx, [.rectL]

        invoke  DrawTextW, [esi+DRAWITEMSTRUCT.hDC], eax, -1, ecx, DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_END_ELLIPSIS

        stdcall FreeMem ; from the stack

; then write the value

        stdcall SymbolToStr, edi
        push    eax
        stdcall utf8ToWideChar, eax
        stdcall StrDel ; from the stack
        push    eax

        lea     ecx, [.rectR]
        invoke  DrawTextW, [esi+DRAWITEMSTRUCT.hDC], eax, -1, ecx, DT_SINGLELINE or DT_LEFT or DT_VCENTER
        stdcall FreeMem ; from the stack.

.cleanup:
        invoke  DeleteObject, [.bkbrush]
        or      eax, -1
        clc
        return

        enddispatch
endp



cVirtual    text 'virtual'


proc SymbolToStr, .ptrLabel
begin
        pushad
        mov     edi, [.ptrLabel]

        test    [edi+TLabel.flags], lfDefined
        jz      .notdefined

        stdcall StrNew
        mov     ebx, eax

        mov     cl, [edi+TLabel.DataSize]

        mov     eax, 'b '
        cmp     cl, 1
        je      .sz_ok

        mov     eax, 'w '
        cmp     cl, 2
        je      .sz_ok

        mov     eax, 'dw '
        cmp     cl, 4
        je      .sz_ok

        mov     eax, 'pw '
        cmp     cl, 6
        je      .sz_ok

        mov     eax, 'qw '
        cmp     cl, 8
        je      .sz_ok

        mov     eax, 'tw '
        cmp     cl, 10
        jne     .prefix_ok

.sz_ok:
        stdcall StrCharCat, ebx, eax

.prefix_ok:
; type:
        cmp     [edi+TLabel.type], ltAbsolute
        je      .type_ok

        stdcall StrCharCat, ebx, 'r '

.type_ok:
; registers

        xor     edx, edx
        cmp     [edi+TLabel.SIBEx], 0
        je      .reg_ok2

        or      edx, 1                  ; close the bracket
        stdcall StrCharCat, ebx, '['

        movzx   eax, byte [edi+TLabel.SIBEx+2]
        cmp     eax, 1
        je      .mul_ok1
        test    eax, eax
        jz      .reg_ok1

        add     eax, '0'
        stdcall StrCharCat, ebx, eax
        stdcall StrCharCat, ebx, '*'
        or      edx, 2      ; at lease one register

.mul_ok1:
        movzx   eax, byte [edi+TLabel.SIBEx]
        test    eax, eax
        jz      .reg_ok1

        stdcall GetRegisterName, eax
        stdcall StrCharCat, ebx, eax
        or      edx, 2      ; at lease one register

.reg_ok1:
        movzx   eax, byte [edi+TLabel.SIBEx+3]
        cmp     eax, 1
        je      .mul_ok2
        test    eax, eax
        jz      .reg_ok2

        add     eax, '0'
        test    edx, 2
        jz      @f
        stdcall StrCharCat, ebx, '+'
@@:
        stdcall StrCharCat, ebx, eax
        stdcall StrCharCat, ebx, '*'

.mul_ok2:
        movzx   eax, byte [edi+TLabel.SIBEx+1]
        test    eax, eax
        jz      .reg_ok2

        stdcall GetRegisterName, eax
        stdcall StrCharCat, ebx, eax

.reg_ok2:
        mov     ecx, ntsHex or ntsUnsigned

        test    edx, 2   ; is there at least one register?
        jz      .add_number

        mov     eax, [edi+TLabel.ValueHi]
        test    eax, eax
        jns     .add_sign

        mov     ecx, ntsHex or ntsSigned
        jmp     .add_number

.add_sign:
        stdcall StrCharCat, ebx, '+'

.add_number:
        stdcall NumToStr64, [edi+TLabel.ValueLo], [edi+TLabel.ValueHi], ecx
        stdcall StrCharCat, eax, 'h'
        stdcall StrCat, ebx, eax
        stdcall StrDel, eax

        test    edx, 1
        jz      .value_ok

        stdcall StrCharCat, ebx, ']'

.value_ok:
        mov     eax, ebx
        jmp     .finish

.notdefined:
        stdcall StrDup, 'undefined'
        jmp     .finish

.finish:
        mov     [esp+4*regEAX], eax
        popad
        return
endp



proc GetRegisterName, .index
begin
        push    ecx

        mov     ecx, [.index]
        cmp     ecx, $f4
        je      .eip

        cmp     ecx, $f8
        je      .rip

        and     ecx, $0f

        mov     eax, [cSIBStrings+4*ecx]

        mov     ecx, [.index]
        shr     ecx, 4          ; 2, 4 or 8
        mov     ch,  byte [.index]
        and     ch, $0f

        cmp     cl, 2
        je      .finish

        cmp     cl, 4
        jne     .qword

;dword
        cmp     ch, 8
        jb      .e_prefix

        mov     ecx, 'd' shl 16
        cmp     ch, 10
        jb      @f
        shl     ecx, 8
@@:
        or      eax, ecx
        jmp     .finish

.e_prefix:
        shl     eax, 8
        mov     al, 'e'
        jmp     .finish

.qword:
        cmp     ch, 8
        jae     .finish

        shl     eax, 8
        mov     al, 'r'

.finish:
        pop     ecx
        return

.eip:
        mov     eax, 'eip'
        jmp     .finish

.rip:
        mov     eax, 'rip'
        jmp     .finish

endp


iglobal
  cSIBStrings dd 'ax',  'cx',  'dx',  'bx'
              dd 'sp',  'bp',  'si',  'di'
              dd 'r8',  'r9',  'r10', 'r11'
              dd 'r12', 'r13', 'r14', 'r15'

endg





proc CCListProc, .hwnd, .wmsg, .wparam, .lparam
begin

        mov     ebx, [.wmsg]
        dispatch ebx

.ondefault:
        stc
        return

;-----------------------------------------------------------------------
oncase WM_LBUTTONDBLCLK

        invoke  GetParent, [.hwnd]
        invoke  GetPropW, eax, [propOwnerAsmEdit]
        invoke  PostMessageW, eax, WM_KEYDOWN, VK_RETURN, 0
        clc
        return

;-----------------------------------------------------------------------
oncase 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  GetPropW, eax, [propOwnerAsmEdit]
        invoke  PostMessageW, eax, [.wmsg], [.wparam], [.lparam]
        xor     eax, eax
        clc
        return

        enddispatch
endp




proc UpdateCCPosition
  .aepos    AEPOS
  .caret    AECARETXY
  .rect     RECT
;  .workrect RECT
  .word     rw    $100
  .aedit    dd    ?

  .info     MONITORINFO
; benchmark variables
;  .time dd ?
;  .count dd ?
begin
        cmp     [hCCList], 0
        je      .finish

        stdcall WaitForCompiler
        jc      .finish

        invoke  GetPropW, [hCCList], [propOwnerAsmEdit]
        mov     [.aedit], eax

        lea     eax, [.aepos]
        invoke  SendMessageW, [.aedit], AEM_GETPOS, eax, 0

        lea     ebx, [.caret]
        invoke  SendMessageW, [.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

        invoke  MonitorFromWindow, [.aedit], 2
        mov     [.info.cbSize], sizeof.MONITORINFO
        lea     ecx, [.info]
        invoke  GetMonitorInfoW, eax, ecx

        mov     eax, [.info.rcWork.right]
        sub     eax, [.rect.right]
        mov     ecx, [.caret.x0]

        cmp     eax, ecx
        jle     @f
        mov     eax, ecx
@@:
        mov     edx, [.info.rcWork.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  SendMessageW, [.aedit], AEM_GETWORDATCARET, $100, ebx

        stdcall WideCharToUtf8, ebx
        mov     ebx, eax

        cmp     word [.word], '.'
        jne     .localok

        cmp     [hCCPrefix], 0
        jne     .prefixok

        stdcall SearchForLabelPrefixInEditor, [.aedit], [.aepos.caretLine]
        mov     [hCCPrefix], eax

.prefixok:
        cmp     [hCCPrefix], 0
        je      .localok

        stdcall StrInsert, ebx, [hCCPrefix], 0

; here ebx contains a pointer to the whole name including the parent label.
.localok:
        stdcall ClearCCList

        stdcall SearchTree, ebx, ptrLabels
        stdcall StrDel, ebx

        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  GetWindowLongW, [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, TRUE
        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  SetWindowLongW, [hCCList], GWL_USERDATA, edx
        pop     ecx

        test    ecx, ecx
        jz      .destroycc

        invoke  SendMessageW, [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  PostMessageW, [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, .empty
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:
        cmp     byte [.empty], al    ; al is always 0 here
        jne     .yesmatch

        cmp     esi, [.str1]
        je      .notmatch

.yesmatch:
        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 SearchForLabelPrefixInEditor, .editor, .caretY
begin
        push    ecx edx
        stdcall GetEditorFile, [.editor]
        test    eax, eax
        jz      @f
        stdcall SearchForLabelPrefix, [eax+TOpenFile.hFileName], [.caretY]
@@:
        pop     edx ecx
        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, .hFilename, .line
begin
        push    edx esi

        stdcall SearchFileInGlobalIndex, [.hFilename]
        jc      .not_found

        mov     esi, eax        ; pointer to TArray of strinigs for needed file.
        mov     edx, [.line]
        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:
        mov     [.fSkip], 1     ; after processing the label name, skip to the end of the line.

        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
        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

        cmp     byte [esi+1], 4
        jne     .no_file

        mov     eax, [esi+2]
        or      eax, $20202020
        cmp     eax, 'file'
        jne     .no_dd

.yes_dd:
        pop     eax
        stc
        retn

.no_file:
        cmp     byte [esi+1], 2
        jne     .no_dd

        mov     ax, [esi+2]
        or      ax, $2020

        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
begin
        pushad

        stdcall GetFullPathNameUtf8, [.hName1]
        mov     [.hName1], eax

        stdcall StrPtr, eax
        mov     esi, eax
        mov     ecx, [esi+string.len]

        stdcall GetFullPathNameUtf8, [.hName2]
        mov     [.hName2], eax

        stdcall StrPtr, eax
        mov     edi, eax

        cmp     ecx, [edi+string.len]
        jne     .not_equal

        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