| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# textwing.htm
Data
CodePages
Data
Unicode
Procedures
AutodetectEncoding
ConvertText
Copy2Clipboard
CreateIndexFile
CreateOutputFile
FindText
InitScrollInfo
LoadAndIndex
LoadInputFile
MainGui
MakeIndex
MsgLoopFind
ReadFileIni
WindowTitle
WndCreateFind
WndCreateMain
WndFont
WndPaintMain
WndPaintMarks
WndProcFind
WndProcMain
WndResizeFind
WndResizeMain

This is a module of EuroTool program EuroView for Windows.

             EUROASM CPU=X64, SIMD=Yes, Unicode=No
    textwing PROGRAM Format=COFF, Width=64, MaxExpansions=256K
              %DROPMACRO *
              INCLUDEHEAD argument.htm
              INCLUDE1 winansi.htm,fastcall.htm,winabi.htm,winsgui.htm,winsdlg.htm,winsfile.htm,winf64.htm
              INCLUDE1 cpuext64.htm,cpuext.htm,status32.htm,memory64.htm,string64.htm
              LINK ../objlib/winapi.lib

↑ Unicode
  declares Unicode Points and their categories. They are tossed by the macro UCP into sections of `[.rodata]` segment.
  These sections are named `[CodePoint]` (WORD) and `[Relevance]` (BYTE).
  Sections `[Translit]` (DWORD) and `[Entity]` (QWORD) are not used in EuroText program.
  All sections have the same number of members.

    [.rodata]                    ; Declare global symbol at the beginning of each section:
     [CodePoint]                 ; Switch to section [CodePoint].
       CodePoint:                ; Label indicating the start of the section.
     [Relevance]                 ; Switch to section [Relevance].
       Relevance:                ; Label indicating the start of the section.

    ; Declare macroinstruction UCP which interprets the lines of UnicodePoints and populates sections [CodePoint] and [Relevance].
    UCP %MACRO CodePoint, Relevance, Translit, Entity
     [CodePoint]                 ; Switch to section [CodePoint].
         DW 0x%CodePoint         ; Define code point (unsigned word), e. g. 0x0000, 0x0001,..0xFFFF.
     [Relevance]                 ; Switch to section [Relevance].
         DB %Relevance           ; Define relevance of each code point (signed byte), e. g. Cc (-32), Nd (+16) etc.
     %ENDMACRO UCP

      INCLUDE unicode.htm        ; Expand the macro UCP with each line of the table UnicodePoints.

     [CodePoint]
       CodePointEnd:             ; Label indicating the end of the section.

↑ CodePages
  declares translation tables. Fields of the table CodePages:
  CPid is numeric identifier 0..65535 in Microsoft assignment;
  CPname is encoding display name, e.g. `"ISO-8859-2"`;
  CPaltName defines alternative names (AlsoKnownAs) and other remarks, e.g. `"Latin 2 (Central European)"`;
  CPurl is URL of authoritative source, e.g. `https://en.wikipedia.org/wiki/Windows-1250` (not used in this program);
  CPtable is 0 or 128 words (4 hexadecimal digits) with corresponding BMP codepoint of upper 128 characters. CPtable is omitted in ASCII and Unicode encodings.
  Members CPid are tossed by the macro CP into section `[CPid]`.
  Members CPname and CPaltName are zero terminated and stored in section `[CPname]` one after another..
  Translation tables are stored in section `[CPtable]` one after another. The first six tables are omitted.

    [.rodata]                    ; Declare symbol at the beginning of each section of segment [.rodata]
     [CPid]
       CPid:
     [CPname]
       CPname:
     [CPtable]
       CPtable:

    ; Declare macroinstruction CP which interprets the lines of CodePages and populates sections [CPid], [CPname] and [CPtable].
    CP %MACRO CPid, CPname, CPaltName, CPurl, CPtable
     [CPid]                      ; Switch to section [CPid].
       DW %CPid                  ; Define encoding identifier, e. g. 437, 667,,,28606.
     [CPname]                    ; Switch to section [CPname].
       DB %CPname,0,%CPaltName,0 ; Join name and alternative name.
     [CPtable]                   ; Switch to section [CPtable].
      %IF "%CPtable" !=== ""     ; The first six encodings don't have translation table, omit them.
    i %FOR 1..128                ; Define 128 words of translation table for each encoding.
        DW 0x%5                  ; Member of CPtable, e. g. 00C7, 00FC etc.
        %SHIFT 1                 ; Take the next member of the table.
      %ENDFOR i                  ; Repeat the definition 128 times.
      %ENDIF
     %ENDMACRO CP

      INCLUDE codepage.htm       ; Expand the macro CP with each line of the table CodePages.
     [CPid]
       CPidEnd:                  ; Declare symbol at the end of section [CPid]. Size of the section is CPidEnd-CPid.

↑ Data

    LST_INDEX  STRUC               ; Strucure of the index records.
    .FA   D DWORD                  ; Offset of the line from InputPtrUTF16 (file address).
    .Size D DWORD                  ; Size of the line in bytes minus CR+LF at the end.
      ENDSTRUC LST_INDEX           ; LST_INDEX.Size has the size completed with two flags:
    FlagWrap         = 0x8000_0000 ; This line is word-wrapped; put french quote at Cols-2.
    FlagFound        = 0x4000_0000 ; This line contains the found text.
    NoFlags          = 0x3FFF_FFFF ; Other bits contains the actual line size.
                                   ; Numeric constants.
    ColorRem         = 0x00E0FFFF  ; Background.
    Color3           = 0x00D0D0FF  ; Found text and marker.
    Color4           = 0x00FFD0D0  ; Selected text.
    OptimalWidthMain = 480
    MinimalWidthMain =  40
    MinimalHeightMain = 440
    IdEncoding       = 0x8031
    IdHelp           = 0x8040
    IdBtnCancel      = 0x8051
    IdBtnFind        = 0x8053
    IdBtnClear       = 0x8054
    heBtnIO          =  20        ; Position of Arg subwindows.
    heFind           = 160
    heTitle1         =  18
    wiBorder         =  10
    wiBtnIO          =  90
    wiFind           = 480
    wiHelp           = 580
    wiTitleEncoding  = 480
    yFindButton      =  60
    FontSizeMax      = 48
    FontSizeDef      = 16        ; Standard font height to begin with.
    FontSizeMin      = 10
    CtrlStep         =  5        ; Cursor keys move the screen by 1, or by CtrlStep characters when Shift is pressed.
    WheelPerLine     = 40        ; wParamHigh = 120 or -120 to scroll 3 rows up or down.
    [.rodata]                    ; Text constants.
    EuroText:       DB "EuroText",0
    Version:        DB " version %^Date",0
    TitleWindowFind DB "EuroTextFind",0
    Ext_index       DU ".index",0    ; Extension of index file.
    Ext_lst         DU ".lst",0      ; Extension of temporary file.
    Configuration:     ; Factory default contents of eurotext.ini. UTF-8.
                    DB 0xEF,0xBB,0xBF,13,10,                                                      \
    "; Configuration file of the text viewer EuroText.",13,10,                                    \
    "InputFile=        ; The file to view. It must be specified, usually at the cmd-line.",13,10, \
    "OutputFile=       ; Temporary; default is ""%%TEMP%%\%%InputFile%%.lst"".",13,10,            \
    "InputEncoding=    ; Default is Autodetect.",13,10,                                           \
    "WrapLines=no      ; Break long lines which do not fit to window.",13,10,                     \
    "LeaveTemporary=no ; Do not erase temporary files when EuroText terminates.",13,10,0
    Spaces:         DB 10,32,32,32,0
    HelpText:          ; Displayed on the key F1 and when no input file is specified.
    DB 10              ; Line Feed.
    DB " is a viewer of text files, which may be written in",10
    DB " UTF-8, UTF-16, UTF-32 or in one of 75 OEM or ANSI 8-bit encodings.",10
    DB " It uses monospace font; control characters are replaced with space.",10,10
    DB " Name of the viewed file can be specified on the command line, for instance",10
    DB "   eurotext.exe ""C:\Users\MyDocuments\InputFile.txt""",10,10
    DB " Or it may be specified as command-line arguments:",10
    DB " /InputFile=",9,9,"(input file name to be viewed)",10
    DB " /OutputFile=",9,9,"(output file | directory for temporary file. Default is %%TEMP%%.)",10
    DB " /InputEncoding=",9,9,"(use autodetect when it's not specified)",10
    DB " /WrapLines=no",9,9,"(break long lines which do not fit to window)",10
    DB " /LeaveTemporary=no",9,"(do not erase temporary output file when EuroText terminates)",10,10
    DB " Parameters may be also specified in this program with keys:",10
    DB "Esc",9,9,9,"(close the window, exit program)",10
    DB " F1",9,9,9,"(this help)",10
    DB " O",9,9,9,"(open an other input file)",10
    DB " S",9,9,9,"(specify a temporary output file name)",10
    DB " E",9,9,9,"(select encoding of input file)",10
    DB " F",9,9,9,"(find a string in the text)",10
    DB " N or Tab",9,9,"(find the next occurence of this string)",10
    DB " P or Shift-Tab",9,9,"(find the previous occurence)",10
    DB " W",9,9,9,"(wrap | unwrap long lines)",10
    DB " +",9,9,9,"(increase font size)",10
    DB " -",9,9,9,"(decrease font size)",10
    DB " 0",9,9,9,"(default font size)",10
    DB " A",9,9,9,"(mark the entire text for CopyPaste",10
    DB " C",9,9,9,"(copy the marked text to clipboard",10
    DB " Home",9,9,9,"(go to the beginning of text)",10
    DB " End", 9,9,9,"(go to the end of text)",10
    DB " PgUp | PgDn",9,9,"(page up | down)",10,10
    DB " Right mouse button will show the corresponding {row}[column]",10
    DB "  right after the file name in the window title.",10
    DB 0
    BOM_UTF32BE         DB 0x00,0x00,0xFE,0xFF
    BOM_UTF32LE         DB 0xFF,0xFE,0x00,0x00
    BOM_UTF16BE         DB 0xFE,0xFF
    BOM_UTF16LE         DB 0xFF,0xFE
    BOM_UTF8            DB 0xEF,0xBB,0xBF

    [.bss]                        ; Working memory variables.
    FileIni             DS FILE64 ; Configuration FILE64.
    FileInput           DS FILE64 ;  Input FILE64.
    FileOutput          DS FILE64 ; Temporary UTF-16 FILE64.
    FileIndex           DS FILE64 ; Temporary FILE64 with LST_INDEX records.
    Msg                 DS MSG                    ; Window message.
    WndClassEx          DS WNDCLASSEX             ; Window class structure.
    InpFileDlg          DS OPENFILENAME
    OutFileDlg          DS OPENFILENAME
    PaintStruct         DS PAINTSTRUCT
    RectWindowMain      DS RECT
    TextMetric          DS TEXTMETRICA
    ScrollInfo          DS SCROLLINFO
    TopLine             EQU ScrollInfo.nPos       ; Ordinal of listing line displayed in the top row of screen.
    Rows                EQU ScrollInfo.nPage      ; Number of rows in current window.
    Lines               EQU ScrollInfo.nMax       ; Number of physical lines in listing.
    GuiInputFile        D MAX_PATH_SIZE * U       ; GUI-maintained arguments in text form, UTF-16.
    GuiOutputFile       D MAX_PATH_SIZE * U
    GuiFindText         D MAX_PATH_SIZE * U
    WorkingString       D 2K*B    ; Temporary working space for file names in UTF-16 and for displayed line.
    ShortString         D 280*B   ; Temporary working space for file names in UTF-8.
    Encoding$           D 32*BYTE ; Encoding name in ASCIIZ, e.g. "IBM867",0
    InputPtr            D QWORD   ; FileInput loaded in memory.
    InputEnd            D QWORD   ; End of FileInput loaded in memory.
    InputSize           D QWORD   ; Input file size.
    InputPtrUTF16       D QWORD   ; FileInput converted do UTF16 and loaded in memory.
    InputEndUTF16       D QWORD   ; End of FileInput loaded in memory.
    InputSizeUTF16      D QWORD   ; Input file size.
    IndexPtr            D QWORD   ; Start of FileIndex loaded in memory.
    IndexEnd            D QWORD   ; End of FileIndex loaded in memory.
    hPen                D QWORD   ; Handle of the pen for painting marks in scrollbar.
    hBackground         D QWORD   ; Handle of the background.
    hFont               D QWORD   ; Handle of the used font.
    hDC                 D QWORD   ; Handle of device context.
    hWindowMain         D QWORD   ; Window handles.
    hWindowEnc          D QWORD
    hWindowHelp         D QWORD
    hWindowFind         D QWORD
    hEditFind           D QWORD
    hBtnCancel          D QWORD
    hBtnClear           D QWORD
    hBtnFind            D QWORD
    cxWindow            D QWORD   ; Horizontal coordinate in px.
    cyWindow            D QWORD   ; Vertical coordinate in px.
    WorkingStringEnd    D QWORD   ; Pointer at the end of WorkingString.
    CodePointLength     D DWORD   ; Number of members in UnicodePoints table (1227).
    CodePagesLength     D DWORD   ; Number of members in CodePages table (1+5+75=81).
    WindowMainWidth     D DWORD   ; Client area width  in px.
    WindowMainHeight    D DWORD   ; Client area height in px.
    WindowFindWidth     D DWORD   ; Number of characters in FindText.
    FontSize            D DWORD   ; Height of font in px.
    cxChar              D DWORD   ; Width  of one character in px.
    cyChar              D DWORD   ; Height of one character in px.
    Cols                D DWORD   ; Number of character columns in current window.
    DocCol              D DWORD   ; Column in document when mouse was clicked (1..)
    DocRow              D DWORD   ; Row in document when mouse was clicked (1..Lines)
    DocRowStart         D DWORD   ; Start row when left MB down. Used to mark selection for clipboard.
    DocColStart         D DWORD   ; Start col when left MB down.
    DocRowStop          D DWORD   ; Stop row when left MB up.
    DocColStop          D DWORD   ; Stop col when left MB up.
    WheelCnt            D DWORD   ; Accumulated WheelPerLine value when mouse wheel is rolled.
    FoundCnt            D DWORD   ; How many time was GuiFindText found.
    LineFound           D DWORD   ; Number of line with found text (1,2,3,,,Lines).
    yTitleHeight        D DWORD   ; Dimension of title strip in pixels.
    yScrollArrowSize    D DWORD   ; Dimension of arrow field on scroller.
    FindTextLength      D DWORD   ; Size of FindText in unichars.
    ArgNr               D BYTE    ; Ordinal number of the current cmd-line argument.

MainGui
  Entry point of EuroText.

    [.text]
    Main:: PROC
        ; Prepare database sections.
        LEA RSI,[CPid:]
        LEA RCX,[CPidEnd:]
        SUB RCX,RSI
        SHR ECX,1
        MOV [CodePagesLength],ECX
        LEA RSI,[CodePoint:]
        LEA RCX,[CodePointEnd:]
        SUB RCX,RSI
        SHR ECX,1
        MOV [CodePointLength],ECX
        ; Try to load arguments from the configuration file "%AppData%\eurotool\eurotext.ini".
        MOVW [WorkingString],0x00
        WinABI GetEnvironmentVariableW,=U'AppData',WorkingString,SIZE# WorkingString
        TEST RAX
        JZ .20:
        Concat$ WorkingString,WorkingString,=U'\eurotool\eurotext.ini',Unicode=yes
        LEA RBX,[FileIni]
        FileAssign RBX,WorkingString,Unicode=yes
        FileExists? RBX
        JNC .10:
        FileMkDir RBX                      ; Create configuration file if it didn't exist.
        GetLengthUTF8 Configuration
        FileStore RBX,Configuration,RCX
    .10:CALL ReadFileIni                   ; Read arguments from the configuration file. Ignore errors.
    .20:; Read arguments from the command-line.
        MOVZX EAX,[ArgNr]
        INC EAX                  ; The next argument.
        MOV [ArgNr],AL
        GetArg RAX,Unicode=yes   ; RSI,RCX returns one argument in UTF-16, e. g. /IF="Sometext.txt" or SomeText.txt.
        JC .30:                  ; When they are no more arguments.
        SHR ECX,1
        LEA RDI,[ShortString]
        WinABI WideCharToMultiByte,65001,0,RSI,RCX,RDI,SIZE#ShortString/2,0,0 ; Convert it to UTF-8 in ShortString.
        MOVB [RDI+RAX],0         ; Zero terminate.
        MOV RSI,RDI
        GetLength$ RSI,Unicode=no; Returns number of bytes in RCX.
        CALL ArgParse::          ; Use ArgParse to translate UTF-8 string RSI,RCX to a public symbol Arg***.
        JMP .20:                 ; Ignore errors, read the next argument.
    .30:                         ; Arguments are done.
        CALL WndCreateMain
        WinABI ShowWindow,[hWindowMain],SW_SHOWNORMAL
        MOV EAX,FontSizeDef
        MOV [FontSize],EAX
        CALL WndFont
        CMPB [ArgInputFile::],0
        JNZ .40:
        WinABI ShowWindow,[hWindowHelp],SW_SHOW
        WinABI UpdateWindow,[hWindowMain]
        JMP .50:
    .40:CALL LoadAndIndex
        ; Viewed file is mapped between [InputPtrUTF16]..[InputPtrUTF16].
        ; Index file is now mapped between [IndexPtr]..[IndexEnd].
    .50:MOVD [TopLine],1
        RstSt [Status::],ArgMouseCaptured
    .MsgLoop:
        WinABI GetMessage, Msg,0,0,0
        TEST RAX
        JZ .MsgQuit:
        WinABI TranslateMessage, Msg                ; Remap character keys from national keyboards.
        WinABI DispatchMessage,  Msg                ; Let Windows call our WndProc.
        JMP .MsgLoop:                               ; Wait for another message.
    .MsgQuit:
        FileClose FileIndex,FileOutput,FileInput
        JSt [Status::],ArgLeaveTemporary,.90:
        FileDelete FileIndex,FileOutput
    .90:TerminateProgram
       ENDP Main

WndCreateMain
  Register class, create the main window plus its child windows.

    WndCreateMain PROC
        MOVD [WndClassEx.cbSize],SIZE# WNDCLASSEX    ; Prepare common properties of three window classes.
        MOVD [WndClassEx.style],CS_HREDRAW|CS_VREDRAW
        WinABI GetModuleHandle,0
        MOV  [WndClassEx.hInstance],RAX
        WinABI LoadIcon,RAX,1             ; The 1st and only icon from [.rsrc] section.
        MOVQ [WndClassEx.hIcon],RAX
        WinABI LoadCursor,0,IDC_ARROW
        MOVQ [WndClassEx.hCursor],RAX
        WinABI CreateSolidBrush,ColorRem
        MOV [hBackground],RAX
        MOV [WndClassEx.lpfnWndProc],WndProcMain
        MOV [WndClassEx.lpszClassName],EuroText
        WinABI RegisterClassExA, WndClassEx    ; Register WndClassEx for the main window.
        WinABI CreateWindowExA,0, \            ; Create the main window.
               EuroText,EuroText,WS_OVERLAPPEDWINDOW|WS_VSCROLL,             \
               CW_USEDEFAULT,CW_USEDEFAULT, OptimalWidthMain*2,MinimalHeightMain*2,  \
               0, 0, [WndClassEx.hInstance], 0
        MOV [hWindowMain],RAX
        ; Create child window for help.
        Concat$ WorkingString, Spaces, EuroText, Version, HelpText
        WinABI CreateWindowEx,0,=B"STATIC",WorkingString, \
               WS_CAPTION | WS_CHILD | SS_LEFT, \
               30,40, wiHelp, 32*heBtnIO, \
               [hWindowMain], IdHelp, [WndClassEx.hInstance],0
        MOV [hWindowHelp],RAX
        ; Create child window for the selection of encoding.
        WinABI CreateWindowEx,0,=B"LISTBOX",=B"Encoding", \
               WS_CAPTION|WS_VSCROLL|WS_CHILD | LBS_NOTIFY, \
               280 ,80,  wiTitleEncoding, 18*heBtnIO, \
               [hWindowMain], IdEncoding, [WndClassEx.hInstance],0
        MOV [hWindowEnc],RAX
        ; Initialize InputFileSelect dialogue.
        LEA RDI,[InpFileDlg]
        MOV ECX,SIZE# OPENFILENAME / 4
        XOR EAX,EAX
        REP STOSD
        MOV [InpFileDlg.lStructSize],SIZE# OPENFILENAME
        MOV RAX,[hWindowMain]
        MOV [InpFileDlg.hwndOwner],RAX
        LEA RSI,[GuiInputFile]
        MOV [InpFileDlg.lpstrFile],RSI
        WinABI MultiByteToWideChar,65001,0,ArgInputFile::,-1,RSI,MAX_PATH_SIZE ; initialize GuiInputFile from ArgInputFile.
        MOV [InpFileDlg.nMaxFile],MAX_PATH_SIZE
        MOV [InpFileDlg.Flags],OFN_FILEMUSTEXIST+OFN_PATHMUSTEXIST
        ; Initialize OutputFileSelect dialogue.
        LEA RDI,[OutFileDlg]
        MOV ECX,SIZE# OPENFILENAME / 4
        XOR EAX,EAX
        REP STOSD
        MOV [OutFileDlg.lStructSize],SIZE# OPENFILENAME
        MOV RAX,[hWindowMain]
        MOV [OutFileDlg.hwndOwner],RAX
        LEA RSI,[GuiOutputFile]
        MOV [OutFileDlg.lpstrFile],RSI
        WinABI MultiByteToWideChar,65001,0,ArgOutputFile::,-1,RSI,MAX_PATH_SIZE ; Convert UTF-8 to UTF-16, initialize GuiOutputFile from ArgOutputFile.
        MOV [OutFileDlg.nMaxFile],MAX_PATH_SIZE
        ; Fill the encoding-selection window.
        WinABI SendMessage,[hWindowEnc],LB_ADDSTRING,0,=B"Autodetect"
        LEA RSI,[CPname:]
        LEA RBX,[CPid:]
        MOV ECX,[CodePagesLength]
        LEA RDI,[Encoding$]      ; Space for encoding name construction.
    .40:LODSB                    ; First encoding name.
        STOSB
        CMP AL,0
        JNZ .40:
        MOVB [RDI-1],' '         ; Replace 0 with space.
    .50:LODSB                    ; Second encoding name.
        STOSB
        CMP AL,0
        JNZ .50
        LEA RDI,[Encoding$]
        WinABI SendMessage,[hWindowEnc],LB_ADDSTRING,0,RDI
        MOVZXW EAX,[RBX]
        ADD RBX,2
        DEC ECX
        JNZ .40:
        RET
    ENDP WndCreateMain

WndProcMain, hWnd, uMsg, wParam, lParam
  This is a callback procedure which receives and handles messages for the MainWindow. Message parameters are by FastCall convention provided in registers RCX, RDX, R8, R9, we'll save them to shadow space with macro SaveToShadow . Thanks to this their contents will be available by formal names ( `[%hWnd], [%uMsg], [%wParam], [%lParam]`), too, in the entire WndProc body.

  Messages obtained from Windows are dispatched by WndProcMain to their handlers. Unhandled messages are passed to DefWindowProc.

  Window hWindowMain displays the lines from listing (output file). In this example we have window height 5 Rows, file length 10 Lines and Level 0. In Level 1..4 only lines with those number of `#` are selected.
Handler input
  RCX=[%hWnd] is the main window handle (the same as static [hWindowMain].
  RDX=[%uMsg] is message identifier,
  R8=[%wParam] is message w-parameter,
  R9=[%lParam] is message l-parameter.
Handler output
  RAX=0 if the message was completely processed by the handler. Otherwise the message is processed by WinAPI DefWindowProc and RAX outputs its return value.
  Scratch registers RCX,RDX,R8..R11 may be destroyed in the handlers.
  Callee-save registers RBX,RSI,RDI,R12..R15 must be restored, if used in the handlers. This provides macro Uses.
Invoked by
  WinAPI DispatchMessage.

    WndProcMain Procedure hWnd, uMsg, wParam, lParam ; These parameters are provided in RCX,RDX,R8,R9.
        Uses RBX,RSI,RDI,R12,R13,R14,R15 ; It's only necessary if some of callee-save registers was used in this fastcalled procedure.
        SaveToShadow
        ; Fork message uMsg=RDX to its handler using macro Dispatch:
         MOV RBX,RCX
         MOV RSI,R8
         Dispatch EDX, WM_VSCROLL, WM_COMMAND, WM_PAINT,WM_SIZE,WM_DESTROY,WM_KEYDOWN, \ ;;;WM_SYSKEYDOWN,  \
                  WM_MOUSEMOVE,WM_MOUSEWHEEL,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_RBUTTONDOWN ;; , WM_CREATE
    .Def:WinABI DefWindowProc,[%hWnd],[%uMsg],[%wParam],[%lParam]  ; Pass ignored event to DefWindowProc with unchanged arguments.
         JMP .Ret:     ; Go to EndProcedure with result value RAX as returned from DefWindowProc.
         ; All message handlers terminate with a jump to label .Def: or .Ret0:.
         ; Helper subprocedures for keyboard and scrollbox event handlers:
    .GetCtrl2ECX PROC  ; Returns RCX=1 when Ctrl is pressed, otherwise RCX=0. RAX,RDX clobbered.
         WinABI GetKeyState,VK_CONTROL ; Returns bit 15 of RAX set when Ctrl was pressed.
         XOR ECX,ECX
         SAL AX,1      ; Shift MSbit to CF.
         RCL ECX,1     ; Virtual key handlers receive RCX=1 when Ctrl was pressed, otherwise RCX=0.
         RET
        ENDP .GetCtrl2ECX
    .GetShift2ECX PROC ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
         WinABI GetAsyncKeyState,VK_SHIFT  ; Returns bit 15 of RAX set when Shift was pressed.
         XOR ECX,ECX
         SAL AX,1      ; Shift MSbit to CF.
         RCL ECX,1     ; Virtual key handlers receive RCX=1 when Shift was pressed, otherwise RCX=0.
         RET
        ENDP .GetShift2ECX
    .ScrollVer: PROC   ; Scroll vertically until TopLine=ESI.
         ; Saturate proposed TopLine=ESI to the acceptable range 1..Lines.
         TEST ESI
         JS .v1:
         CMP ESI,1
         JAE .v2:
     .v1:MOV ESI,1
     .v2:CMP ESI,[Lines]
         JB .v5:
         MOV ESI,[Lines]
     .v5:MOV [TopLine],ESI
         WinABI SetScrollPos,[hWindowMain],SB_VERT,RSI,1
         WinABI InvalidateRect,[hWindowMain],0,0
         RET
        ENDP .ScrollVer:
    .Mouse2Char: PROC ; Convert mouse coordinates from R9=lParam to RAX (document Row) and RDX (document Col). Clobbers RCX.
         MOV EAX,R9D             ; xPos,yPos when clicked.
         AND EAX,0xFFFF          ; xPos of the mouse click.
         XOR EDX,EDX
         MOV ECX,[cxChar]
         DIV RCX
         PUSH RAX                ; Column.
          MOV EAX,R9D            ; xPos,yPos when clicked.
          SHR EAX,16             ; yPos of the mouse click.
          XOR EDX,EDX
          MOV ECX,[cyChar]
          DIV RCX                ; RAX is vertical position in characters.
          ADD EAX,[TopLine]
         POP RDX
         RET
        ENDP .Mouse2Char:
    .WM_COMMAND:
         CMP R9,[hWindowEnc]
         JNE .C3:
         SHR R8,16
         CMP R8W,2
         JA .Ret0:
         WinABI SendMessage,[hWindowEnc],LB_GETCURSEL,0,0
         CMP EAX,0               ; Autodetect?
         JE .C1:
         CMP AX,[CodePagesLength]
         JA .Ret0:
         LEA RSI,[CPid:]
         MOVZXW EAX,[RSI+2*RAX-2]
    .C1: MOV [ArgInputEncoding::],EAX
         CALL WindowTitle
         CALL LoadAndIndex
         WinABI ShowWindow,[hWindowEnc],SW_HIDE
         WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:
    .C3: CMP R9,[hWindowHelp]
         JNE .Def:
         WinABI ShowWindow,[hWindowHelp],SW_HIDE
         JMP .Ret0:
     .WM_PAINT:
         CALL WndPaintMain
         CALL WndPaintMarks
         JMP .Ret0:
    .WM_SIZE:
         CALL WndFont
         CALL WndResizeMain
         JMP .Def:
    .WM_LBUTTONDOWN:             ; Left mouse button captures mouse and changes marked text to be selected for clipboard.
         SetSt [Status::],ArgMouseCaptured
         XOR EAX,EAX
         MOV [DocRowStop],EAX
         MOV [DocColStop],EAX
         CALL .Mouse2Char:
         MOV [DocRowStart],EAX
         MOV [DocColStart],EDX
         JMP .Ret0:
    .WM_MOUSEMOVE:
         JNSt [Status::],ArgMouseCaptured, .Def:
         CALL .Mouse2Char:
         MOV [DocRowStop],EAX
         MOV [DocColStop],EDX
         WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:
    .WM_LBUTTONUP:
         RstSt [Status::],ArgMouseCaptured
         CALL .Mouse2Char:
         CMP EAX,[DocRowStart]   ; Swap so DocStop is always greater than DocStart.
         JA .50:
         JB .40:
         CMP EDX,[DocColStart]
         JAE .50:
         XCHG EDX,[DocColStart]
         JMP .50:
    .40: XCHG EAX,[DocRowStart]
         XCHG EDX,[DocColStart]
    .50: MOV [DocRowStop],EAX
         MOV [DocColStop],EDX
         WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:
    .WM_RBUTTONDOWN:             ; Right mouse button marks the clicked character
         CALL .Mouse2Char:       ;   and writes its coordinates in the title bar of WindowMain.
         MOV [DocRow],EAX        ; Position to show coordinates in the title bar of WindowMain.
         MOV [DocCol],EDX
         CALL WindowTitle
         WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:
    .WM_MOUSEWHEEL:               ; Rolled.
         SAR ESI,16               ; RSI is now +40 or -40 on mouse-wheel roll.
         ADD [WheelCnt],ESI       ; Accumulate scroll requests.
         MOV EDI,[WheelCnt]
     .RollUp:
         CMP EDI,WheelPerLine
         JL  .RollDown:
         SUB EDI,WheelPerLine
         MOV [WheelCnt],EDI
         WinABI SendMessage,RBX,WM_VSCROLL,SB_LINEUP,0
         JMP .RollUp:
     .RollDown:
         CMP EDI,0
         JGE .Ret0:
         ADD EDI,WheelPerLine
         MOV [WheelCnt],EDI
         WinABI SendMessage,RBX,WM_VSCROLL,SB_LINEDOWN,0
         JMP .RollDown:
    .WM_VSCROLL:       ; User scrolled the window vertically.
         CALL .GetCtrl2ECX
         MOV EAX,0x0000_FFFF
         AND EAX,ESI   ; EAX is now scroll box action.
         SHR ESI,16    ; ESI is now scroll box position.
         Dispatch EAX,SB_LINEUP,SB_LINEDOWN,SB_PAGEUP,SB_PAGEDOWN,SB_THUMBTRACK
         JMP .Def:
    .WM_KEYDOWN:                 ; Non-character hot key ESI=R8D=wParam was pressed.
         CMP R8B,VK_F1
         JB .K2:
         CMP R8B,VK_F10
         JBE .VK_F1:
    .K2: PUSH R8
           CALL .GetShift2ECX    ; Test if [Shift] was pressed. Set RCX=0 when not pressed.
         POP R8
         Dispatch R8B,'O','S','E','F','N','P','W','L','A','C', \
            VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT,VK_HOME,VK_END,     \
            VK_TAB,VK_NUMPAD0,VK_ADD,VK_SUBTRACT,VK_ESCAPE,
         JMP .Def:
    .O:                          ; Key 'O' pressed.
         WinABI MultiByteToWideChar,65001,0,ArgInputFile::,-1,GuiInputFile,MAX_PATH_SIZE ; initialize GuiInputFile from ArgInputFile.
         WinABI GetOpenFileNameW,InpFileDlg
         TEST RAX
         JZ .Ret0:
         WinABI WideCharToMultiByte,65001,0,GuiInputFile,-1,ArgInputFile::,MAX_PATH_SIZE,0,0
         CALL WndResizeMain
         CALL LoadAndIndex
         MOVW [GuiFindText],0
         CALL FindText:
         CALL WindowTitle
         JMP .Ret0:
    .S:                          ; Key 'S' pressed.
         WinABI MultiByteToWideChar,65001,0,ArgOutputFile::,-1,GuiOutputFile,MAX_PATH_SIZE ; initialize GuiInputFile from ArgInputFile.
         WinABI GetOpenFileNameW, OutFileDlg
         TEST RAX
         JZ .Ret0:
         WinABI WideCharToMultiByte,65001,0,GuiOutputFile,-1,ArgOutputFile::,MAX_PATH_SIZE,0,0
         JMP .Ret0:
    .E:  WinABI ShowWindow,[hWindowEnc],SW_SHOW
         LEA RDI,[CPid:]
         MOV RDX,RDI
         MOV ECX,[CodePagesLength]
         MOV EAX,[ArgInputEncoding::]
         REPNE SCASW
         JNE .Ret0:
         SUB RDI,RDX
         SHR EDI,1
         WinABI SendMessage,[hWindowEnc],LB_SETCURSEL,RDI,0
         JMP .Ret0:
    .F:                          ; Key 'F' pressed.
         WinABI IsWindow,[hEditFind]
         JZ .F3:
         WinABI PostMessage,[hEditFind],EM_SETSEL,0,-1  ; Select all.
    .F3: CALL MsgLoopFind        ; Find.
         CALL WindowTitle
    .Inv:WinABI InvalidateRect,[hWindowMain],0,0
         JMP .Ret0:
    .P:  MOV CL,1                ; Key 'P' pressed.
    .N:                          ; Key 'N' pressed.
    .VK_TAB:                     ; Find next (or find previous with Shift).
         MOV EAX,[LineFound]
         TEST EAX
         JZ .Ret0:
         MOV R8,[IndexPtr]
         MOV R9,[IndexEnd]
         MOV RSI,R8
         LEA RSI,[RSI+8*RAX]
         CMP EAX,[Lines]
         JB .T1:
         SUB RSI,SIZE# LST_INDEX
    .T1: JRCXZ .T5:              ; Go to find next.
    .T2: CMP RSI,R8              ; Find previous.
         JA .T3:
         MOV RSI,R9
    .T3: SUB RSI,SIZE# LST_INDEX
         TEST [RSI+LST_INDEX.Size],FlagFound
         JZ .T2:
         JMP .T8:
    .T4: ADD RSI,SIZE# LST_INDEX
    .T5: CMP RSI,R9
         JB .T6:
         MOV RSI,R8
    .T6: TEST [RSI+LST_INDEX.Size],FlagFound
         JZ .T4:
    .T8: SUB RSI,R8
         SHR ESI,3
         INC ESI
         SUB ESI,ECX
         MOV [LineFound],ESI
         DEC ESI
         MOV [TopLine],ESI
         JMP .SB_THUMBTRACK:
    .W:                            ; Key 'W' pressed.
         InvSt [Status::],ArgWrapLines
         MOVW [GuiFindText],0    ; When WrapLines changes, FindText has to be cancelled.
         CALL FindText:
         CALL WindowTitle
         CALL MakeIndex
         CALL InitScrollInfo
         JMP .Inv:
    .L:                          ; Key 'L' pressed.
         InvSt [Status::],ArgLeaveTemporary
         JMP .Def:
    .VK_F1:                      ; Key F1 pressed.
         WinABI ShowWindow,[hWindowHelp],SW_SHOW
         JMP .Ret0:
    .A:  MOV EAX,1               ; Select all.
         MOV [DocRowStart],EAX
         MOV [DocColStart],EAX
         MOV RSI,[IndexEnd]
         LEA RDI,[RSI-SIZE# LST_INDEX]
         SUB RSI,[IndexPtr]
         SHR ESI,3
         MOV [DocRowStop],ESI
         MOV EAX,[RDI+LST_INDEX.Size]
         AND EAX,NoFlags
         DEC EAX
         MOV [DocColStop],EAX
    .C:  CALL Copy2Clipboard:    ; Copy.
         JMP .Inv:
    .SB_LINEDOWN:                ; Vertical scrollbox line down.
    .VK_DOWN:                    ; Down arrow.
         MOV ESI,[TopLine]
         INC ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         ADD ESI,CtrlStep
         JMP .SB_THUMBTRACK:
    .SB_LINEUP:                  ; Vertical scrollbox line up.
    .VK_UP:                      ; Up arrow.
         MOV ESI,[TopLine]
         DEC ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         SUB ESI,CtrlStep
         JMP .SB_THUMBTRACK:
    .SB_THUMBTRACK:              ; User dragged the tumbtrack to the position ESI.
         CALL .ScrollVer:
         JMP .Ret0:
    .SB_PAGEUP:                  ; Vertical scrollbox page up.
    .VK_PRIOR:
         MOV ESI,[TopLine]
         SUB ESI,[Rows]
         INC ESI,ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         SUB ESI,[Rows]
         SUB ESI,[Rows]
         SUB ESI,[Rows]
         JMP .SB_THUMBTRACK:
    .VK_HOME:
         MOV ESI,1
         JMP .SB_THUMBTRACK:
    .SB_PAGEDOWN:                ; Vertical scrollbox page down.
    .VK_NEXT:
         MOV ESI,[TopLine]
         ADD ESI,[Rows]
         DEC ESI,ESI
         JRCXZ .SB_THUMBTRACK:   ; If Ctrl is not pressed.
         ADD ESI,[Rows]
         ADD ESI,[Rows]
         ADD ESI,[Rows]
         JMP .SB_THUMBTRACK:
    .VK_END:
         MOV ESI,[Lines]
         JMP .SB_THUMBTRACK:
    .VK_NUMPAD0:                 ; Ctrl 0 restore font size.
         MOV EDI,FontSizeDef
    .SetFontEDI:
         MOV [FontSize],EDI
         CALL WndFont            ; Get new [cxChar],[cyChar].
         CALL WndResizeMain      ; Recalculate Rows, Cols.
         JMP .Ret0:
    .VK_ADD:                     ; Ctrl + increase font size.
         MOV EDI,[FontSize]
         INC EDI
         CMP EDI,FontSizeMax
         JG .Ret0:
         JMP .SetFontEDI:
    .VK_SUBTRACT:                ; Ctrl - decrease font size.
         MOV EDI,[FontSize]
         DEC EDI
         CMP EDI,FontSizeMin
         JL .Ret0:
         JMP .SetFontEDI:
    .VK_ESCAPE:                  ; Terminate program.
    .WM_DESTROY:                 ; Program terminates.
         WinABI IsWindowVisible,[hWindowEnc]
         TEST EAX
         JZ .D1:
         WinABI ShowWindow,[hWindowEnc],SW_HIDE
         JMP .Ret0:
    .D1: WinABI IsWindowVisible,[hWindowHelp]
         TEST EAX
         JZ .D3:
         WinABI ShowWindow,[hWindowHelp],SW_HIDE
         JMP .Ret0:
    .D3: WinABI ShowWindow,[hWindowMain],SW_HIDE
         WinABI DeleteObject,[hFont]
         WinABI PostQuitMessage,0; Tell Windows to quit this program with errorlevel 0.
    .Ret0:XOR EAX,EAX            ; RAX=0 signalizes that the message was processed here.
    .Ret:EndProcedure WndProcMain

WndResizeMain
  Dimensions of the MainWindow changed. Index of LST_INDEX records in FileIndex will be rebuilt.
Input
  RectWindowMain, cxChar, Status:ArgWrapLines
Output/dt>
  IndexPtr, IndexEnd
Called from
  WndProcMain.WM_SIZE.

    WndResizeMain PROC
        LEA RBX,[RectWindowMain]
        WinABI GetWindowRect,[hWindowMain],RBX
        MOV ESI,[RBX+RECT.left]
        MOV ECX,[RBX+RECT.right]
        SUB ECX,ESI
        CMP ECX,MinimalWidthMain
        JA .10:
        MOV ECX,MinimalWidthMain
    .10:MOV [WindowMainWidth],ECX
        MOV EDI,[RBX+RECT.top]
        MOV EDX,[RBX+RECT.bottom]
        SUB EDX,EDI
        CMP EDX,MinimalHeightMain
        JA .20:
        MOV EDX,MinimalHeightMain
    .20:MOV [WindowMainHeight],EDX
        WinABI MoveWindow,[hWindowMain],RSI,RDI,RCX,RDX,-1
        MOV EAX,[WindowMainWidth]
        XOR EDX,EDX
        MOV ECX,[cxChar]
        TEST ECX
        JZ .90:
        DIV RCX
        DEC EAX
        MOV [Cols],EAX                     ; Number of columns visible in window.
        MOV EAX,[WindowMainHeight]
        XOR EDX,EDX
        MOV ECX,[cyChar]
        JRCXZ .90:
        DIV RCX
        MOV [Rows],EAX                     ; Number of lines visible in window.
        WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,1
        WinABI InvalidateRect,[hWindowMain],0,1
    .90:RET
    ENDP WndResizeMain

WndPaintMain
  Display the lines of text encoded in UTF-16LE, mapped between [InputPtrUTF16]..[InputEndUTF16] using index between IndexPtr..IndexEnd.
  Lines on screen are manipulated with cursor keys by changing the `TopLine` variable.
  | line 1 | line 2 | line 3 ┌──────────────┐ │| line 4 │row 1 `TopLine` = 4 │| line 5 │row 2 │| line 6 │row 3 │| line 7 │row 4 │| line 8 │row 5 `Rows` on screen = 5 └──────────────┘ | line 9 | line 10 `Lines` of listing = 10
[TopLine]
  is saturated to the range 1..Lines-Rows+1.
ClobberECHO s
  .htm >>euroasm.dat R10=LST_INDEX.Size including flags.
  R12=InputPtrUTF16: pointer to the entire text in memory.
  R13=WorkingString: buffer for one line.
  R14=Rows decremented by the number of lines already displayed on screen.
  R15=IndexEnd pointer.
Called from
  WndProcMain.WM_PAINT.

    WndPaintMain PROC
        XOR EAX,EAX
        MOV [cxWindow],RAX
        MOV [cyWindow],RAX
        WinABI BeginPaint, [hWindowMain], PaintStruct
        MOV RBX,RAX
        MOV [hDC],RAX
        WinABI SelectObject, RBX, [hFont]
        WinABI SetBkColor, RBX, ColorRem
        MOV R12,[InputPtrUTF16]
        LEA R13,[WorkingString]
        MOV RSI,[IndexPtr]
        MOV R15,[IndexEnd]
        MOV RCX,R15
        SUB RCX,RSI
        SHR ECX,3                          ; Size of LST_INDEX=8.
        JZ .90:
        MOV [Lines],ECX                    ; Total number of lines in input text.
        MOV EDI,[TopLine]
        CMP EDI,ECX
        JBE .10:
        MOV EDI,ECX
    .10:MOV [TopLine],EDI
        WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,-1
        SUB RSI,SIZE# LST_INDEX
        XOR EDX,EDX
    .15:INC EDX                            ; Line number 1,2,3,,,Lines.
        ADD RSI,SIZE# LST_INDEX
        CMP EDX,EDI                        ; Reached TopLine?
        JB .15:                            ; RSI now idexes the first displayed line.
        MOV R14D,[Rows]                    ; Number of rows on screen.
        CMP EDX,[Lines]
        JA .80:                            ; Jump when reached the end of lines in document.
        ; TopLine reached, start painting.
    .20:; Display lines indexed by RSI until EDX>[Lines] (out of lines) or until R14=0 (all rows displayed).
        CMP RSI,R15                        ; IndexEnd?
        JAE .80:                           ; Go to display empty lines below the document.
        LODSD                              ; LST_INDEX.FA
        LEA RBX,[R12+RAX]
        LODSD                              ; LST_INDEX.Size in bytes.
        MOV R10,RAX
        AND EAX,NoFlags                    ; Erase FlagWrap and FlagFound, if set.
        CMP EAX,800                        ; Limit the line size.
        JB .23:
        MOV EAX,800                        ; Line too long, ignore its tail.
    .23:LEA RDX,[RBX+RAX]                  ; End of listing line characters.
        ; RSI is pointer to LST_INDEX.
        ; RBX..RDX are UTF-16 characters in memory corresponding with this screen line. Trailing CR+LF are omitted.
        ; They will be copied to R13=WorkingString, respecting TAB,BS. Other control characters are replaced with space.
        MOV RDI,R13                        ; Buffer dedicated for one screen line.
        MOV AX,0x0020                      ; The first column is a space.
        STOSW
    .26:CMP RBX,RDX                        ; End of input line?
        JNB .40:
        MOV AX,[RBX]                       ; Load one character.
        ADD RBX,2
        CMP AX,0x0009                      ; Horizontal tabelator?
        JE .38:
        CMP AX,0x0008                      ; Backspace?
        JE .33:
        CMP AX,0x0020                      ; Other control character?
        JBE .30:
        STOSW                              ; Otherwise store the ordinary character.
        JMP .26:
    .30:MOV AX,0x0020                      ; Other control character replace with space.
        STOSW
        JMP .26:
    .33:CMP RDI,R13                        ; Backspace go back one character.
        JBE .26:
        SUB RDI,2
        JMP .26:
    .38:MOV RCX,RDI                        ; Horizontal tabelator replace with spaces.
        ADD RCX,2
        OR  CL,0x0E
        SUB RCX,RDI
        SHR ECX,1
        INC ECX
        MOV AX,0x0020
        REP STOSW                          ; Replace LF with spaces.
        JMP .26:
    .40:; Complete the line at R13=WorkingString with spaces until its length is [Cols].
        MOV RAX,RDI                        ; Pointer inside WorkingString.
        SUB RAX,R13
        SHR EAX,1                          ; Number of characters in line.
        MOV ECX,[Cols]                     ; Visible width of the screen in characters.
        SUB ECX,EAX
        JNA .44:
        TEST R10,FlagWrap
        JZ .42:
        MOV AX,0x00BB                      ; French quotes signalize WrapLine.
        STOSW
    .42:MOV AX,0x0020
        STOSW
        REP STOSW                          ; Fill the rest of line with spaces.
        MOV [WorkingStringEnd],RDI
    .44:MOV RAX,RSI
        SUB RAX,[IndexPtr]
        SHR EAX,3                          ; This line number.
        MOV R8D,[DocColStart]
        MOV R9D,[DocColStop]
        CMP EAX,[DocRowStart]
        JB .56:                            ; Do nothing.
        JE .46:
        XOR R8,R8                          ; The second and next selected lines start from 0.
    .46:CMP EAX,[DocRowStop]
        JA .56:                            ; Do nothing.
        JE .48:
        XOR R9,R9
        DEC R9                             ; Not last line ends at -1.
    .48:; Line contains selected text from R8 (may be 0) to R9 (may be -1).
        ; Display the first part of line from 0 to R8D in ColorRem.
        WinABI SetBkColor, [hDC], ColorRem
        MOV EDI,R8D
        TEST EDI
        JZ .50:
        WinABI TextOutW,[hDC],[cxWindow],[cyWindow],R13,RDI ; Display the first part of line.
    .50:WinABI SetBkColor, [hDC], Color4   ; Switch to emphasized color.
        MOV EAX,[cxChar]
        MUL RDI
        ADD EAX,[cxWindow]                 ; RAX is x-coordinate.
        SHL EDI,1
        ADD RDI,R13                        ; Address in WorkingString.
        MOV RCX,[WorkingStringEnd]
        SUB RCX,R13
        SHR ECX,1
        CMP ECX,R9D
        JB .52:
        MOV ECX,R9D
    .52:SUB ECX,R8D
        INC ECX
        PUSH RCX
          WinABI TextOutW,[hDC],RAX,[cyWindow],RDI,RCX ; Display the second part of line.
          WinABI SetBkColor, [hDC], ColorRem
        POP RCX
        LEA RDI,[RDI+2*RCX]
        MOV RCX,[WorkingStringEnd]
        CMP RDI,RCX
        JNB .54
        SUB RCX,RDI
        SHR ECX,1
        MOV EAX,[cxChar]
        MOV RDX,RDI
        SUB RDX,R13
        SHR EDX,1
        MUL RDX
        WinABI TextOutW,[hDC],RAX,[cyWindow],RDI,RCX ; Display the third part of line.
    .54:JMP .75:
    .56:; Handle the searched text.
        TEST R10,FlagFound                 ; FlagFound in this line?
        JZ .60:
        ; FlagFound is set; display the line with emphasised found text.
        PUSH RSI
         MOV RDI,R13
         LEA RSI,[GuiFindText]
         MOV RCX,R10                       ; Size including flags.
         AND ECX,NoFlags
         SHR ECX,1
         LODSW                             ; The first character of FindText.
    .58: REPNE SCASW                       ; Find it in the whole line.
         PUSH RCX,RSI,RDI
          MOV ECX,[FindTextLength]
          DEC ECX
          REPE CMPSW
         POP RDI,RSI,RCX
         JNE .58:
         SUB RDI,2                         ; Searched text was found.
         SUB RDI,R13
         SHR EDI,1
         WinABI TextOutW,[hDC],[cxWindow],[cyWindow],R13,RDI ; Display the first part of line.
         WinABI SetBkColor, [hDC], Color3
         MOV EAX,[cxChar]                  ; Width of a character in pixels.
         MUL RDI
         ADD EAX,[cxWindow]
         SHL EDI,1
         ADD RDI,R13
         MOV ESI,[FindTextLength]          ; In unichars.
         WinABI TextOutW,[hDC],RAX,[cyWindow],RDI,RSI ; Display the emphasised FindText.
         WinABI SetBkColor, [hDC], ColorRem
         LEA RDI,[RDI+2*RSI]
        POP RSI
        MOV RAX,RDI
        SUB RAX,R13
        MOV ECX,[Cols]
        MOV EDX,EAX
        SHR EDX,1
        SHR EAX,1
        SUB ECX,EDX
        MUL [cxChar]
        WinABI TextOutW,[hDC],RAX,[cyWindow],RDI,RCX ; Display the rest of line.
        JMP .75:
    .60:; This line does not contain found text. Change background of a character at {DocRow}[DocCol].
        JSt [Status::],ArgWrapLines,.70:   ; When /WL=true, do not change background.
        ; Change background color of one character at {DocRow}[DocCol].
        MOV EAX,[TopLine]
        ADD EAX,[Rows]
        SUB EAX,R14D
        CMP EAX,[DocRow]
        JNE .70:                           ; Jump if this line is not [DocRow].
        ; Background color of character at {DocRow}[DocCol]:
        MOV ECX,[DocCol]
        JRCXZ .65:
        WinABI TextOutW,[hDC],[cxWindow],[cyWindow],R13,RCX ; Display the first part of line.
    .65:WinABI SetBkColor, [hDC], Color3
        MOV ECX,[DocCol]
        MOV EAX,ECX
        MULD [cxChar]
        ADD EAX,[cxWindow]
        LEA RCX,[R13+2*RCX]
        WinABI TextOutW,[hDC],RAX,[cyWindow],RCX,1          ; Display emphatized character.
        WinABI SetBkColor, [hDC], ColorRem
        MOV RDI,[Cols]
        MOV ECX,[DocCol]
        SUB RDI,RCX
        INC ECX
        MOV EAX,ECX
        MUL [cxChar]
        ADD EAX,[cxWindow]
        LEA RCX,[R13+2*RCX]
        WinABI TextOutW,[hDC],RAX,[cyWindow],RCX,RDI         ; Display the rest of line.
        JMP .75:
    .70:WinABI TextOutW,[hDC],[cxWindow],[cyWindow],R13,[Cols]  ; Display the entire line normally.
    .75:MOV EAX,[cyChar]
        ADD [cyWindow],EAX
        DEC R14
        JNZ .20:                 ; Go to display the next line.
    .80:MOV RDI,R13              ; Fill the line at the end with spaces.
        MOV AX,0x0020
        MOV ECX,[Cols]
        ADD ECX,32
        REP STOSW
    .85:TEST R14,R14
        JZ .90:
        DEC R14
        MOV EAX,[Cols]
        WinABI TextOutW,[hDC],[cxWindow],[cyWindow],R13,RAX ; Display spaces on the entire line.
        MOV EAX,[cyChar]
        ADD [cyWindow],EAX
        JMP .85:
    .90:WinABI EndPaint, [hWindowMain], PaintStruct
        RET
       ENDP WndPaintMain

WndPaintMarks
  Paint little red marks on the right side of the main window to indicate the found text.
Clobbers
  R12=Number of lines * 8
  R13=WindowHeight netto without title size and both scroll arrows.
  R14=device context of WindowMain
  R15=IndexEnd

    WndPaintMarks PROC
        CMPW [GuiFindText],0
        JZ .90:
        WinABI GetSystemMetrics,SM_CYVSCROLL
        ADD EAX,4
        MOV [yScrollArrowSize],EAX
        LEA EBX,[2*EAX]
        WinABI GetSystemMetrics,SM_CYSIZE
        ADD EAX,4
        MOV [yTitleHeight],EAX
        MOV R13D,[WindowMainHeight]
        ADD EBX,EAX
        SUB R13,RBX
        MOV RSI,[IndexPtr]
        MOV R12,[IndexEnd]
        MOV R15,R12
        SUB R12,RSI              ; R12=number of lines * 8
        WinABI GetWindowDC,[hWindowMain]
        MOV R14,RAX
        WinABI CreatePen,PS_SOLID,3,Color3 ; 0x00112233
        MOV [hPen],RAX
        WinABI SelectObject,R14,RAX
        SUB RSI,SIZE# LST_INDEX
    .50:ADD RSI,SIZE# LST_INDEX
        CMP RSI,R15
        JAE .80:
        TEST [RSI+LST_INDEX.Size],FlagFound
        JZ .50:
        MOV RAX,RSI
        SUB RAX,[IndexPtr]
        INC EAX
        MUL R13
        DIV R12
        ADD EAX,[yTitleHeight]
        ADD EAX,[yScrollArrowSize]
        MOV EBX,[WindowMainWidth]
        MOV EDI,EAX
        SUB EBX,28
        WinABI MoveToEx,R14,RBX,RDI,0
        ADD RBX,30
        WinABI LineTo,R14,RBX,RDI
        JMP .50:
    .80:WinABI DeleteObject,[hPen]
        WinABI ReleaseDC,[hWindowMain],R14
    .90:RET
        ENDP WndPaintMarks

MsgLoopFind
  Message handling procedure of child window for getting the searched text.

    MsgLoopFind PROC
         WinABI IsWindow,[hWindowFind]
         TEST EAX
         JNZ .10:
         CALL WndCreateFind                ; Window for retrieving searched text.
    .10: WinABI PostMessage,[hEditFind],EM_SETSEL,0,-1  ; Select all searched string..
         WinABI ShowWindow,[hWindowFind],SW_SHOW
         WinABI UpdateWindow,[hWindowFind]
    .MsgLoop:
         WinABI GetMessage, Msg,0,0,0
         TEST RAX
         JZ .MsgQuit:                      ; ZF signalizes message WM_QUIT - request for termination.
         CMPD [Msg.wParam],VK_ESCAPE
         JNE .30:
         WinABI PostMessage,[hWindowFind],WM_KEYDOWN,VK_ESCAPE,0
         JMP .MsgQuit:
    .30: CMPD [Msg.wParam],VK_RETURN
         JNE .40:
         WinABI PostMessage,[hWindowFind],WM_KEYDOWN,VK_RETURN,0
         JMP .MsgQuit:
    .40: WinABI IsDialogMessage,[hWindowFind],Msg     ; Let Windows handle TAB keys.
         TEST RAX
         JNZ .MsgLoop:
    .50: WinABI TranslateMessage, Msg      ; Remap character keys from national keyboards.
         WinABI DispatchMessage,  Msg      ; Let Windows call our WndProc.
         JMP .MsgLoop:                     ; Wait for another message.
    .MsgQuit:
         WinABI ShowWindow,[hWindowFind],SW_HIDE
         XOR EAX,EAX
         RET                               ; Return to CUI module.
       ENDP MsgLoopFind

WndCreateFind
  Register window class, create nonmodal window and all its subwindows.

    WndCreateFind   PROC
        ; Register WndClassEx for the main window.
        MOVQ [WndClassEx.lpszClassName],TitleWindowFind
        MOVQ [WndClassEx.lpfnWndProc],WndProcFind
        WinABI RegisterClassExA, WndClassEx
        ; Create the Find window.
        WinABI CreateWindowExA,0,                                     \
               TitleWindowFind,=B"EuroText find",WS_OVERLAPPEDWINDOW, \
               CW_USEDEFAULT,CW_USEDEFAULT,wiFind,heFind,             \
               0, 0, [WndClassEx.hInstance], 0
        MOV [hWindowFind],RAX
        ; Create child windows of the WindowFind.
        ; Find edit.
        MOV ESI,wiFind-2*wiBorder
        WinABI CreateWindowExW,0,=U'EDIT',GuiFindText,WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
               wiBorder,wiBorder,RSI,heTitle1,[hWindowFind],0,[WndClassEx.hInstance],0
        MOV [hEditFind],RAX
        WinABI SetFocus,RAX
        MOV ECX,wiFind-wiBorder-wiBtnIO
        WinABI CreateWindowExA,0,=B'BUTTON',=B"&Find",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP+BS_DEFPUSHBUTTON, \
               RCX,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnFind,[WndClassEx.hInstance],0
        MOV [hBtnFind],RAX       ; Button Find.
        WinABI CreateWindowExA,0,=B'BUTTON',=B"C&lear",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
               wiBorder+wiBtnIO+wiBorder,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnClear,[WndClassEx.hInstance],0
        MOV [hBtnClear],RAX      ; Button Clear.
        WinABI CreateWindowExA,0,=B'BUTTON',=B"&Cancel",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
               wiBorder,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnCancel,[WndClassEx.hInstance],0
        MOV [hBtnCancel],RAX     ; Button Cancel.
        RET
       ENDP WndCreateFind

WndProcFind, hWnd, uMsg, wParam, lParam
  This is a callback procedure which receives and handles messages for the WindowFind.
  Window Find has EDIT field for the searched text and buttons [Cancel], [Clear], [Find].
Handler input
  RCX=[%hWnd] is the main window handle (the same as static [hWindowArg].
  RDX=[%uMsg] is message identifier,
  R8=[%wParam] is message w-parameter,
  R9=[%lParam] is message l-parameter.
Handler output
  RAX=0 if the message was completely processed by the handler. Otherwise the message is processed by WinAPI DefWindowProc and RAX outputs its return value.
  Scratch registers RCX,RDX,R8..R11 may be destroyed in the handlers.
  Callee-save registers RBX,RSI,RDI,R12..R15 must be restored, if used in the handlers. This provides macro Uses.
Invoked by
  WinAPI DispatchMessage.

    WndProcFind Procedure hWnd, uMsg, wParam, lParam ; These parameters are provided in RCX,RDX,R8,R9.
        SaveToShadow
        Uses RBX,RSI,RDI,R12,R13,R14,R15 ; It's only necessary if some of callee-save registers was used in this fastcalled procedure.
        CALL .GetShift2ECX:
        ; Fork message uMsg=RDX to its handler using macro Dispatch:
         Dispatch EDX, WM_DESTROY, WM_SIZE, WM_KEYDOWN, WM_SYSKEYDOWN, WM_COMMAND
    .Def:WinABI DefWindowProc,[%hWnd],[%uMsg],[%wParam],[%lParam]  ; Pass ignored event to DefWindowProc with unchanged arguments.
         JMP .Ret:  ; Go to EndProcedure with result value RAX as returned from DefWindowProc.
         ; All message handlers terminate with a jump to label .Def: or .Ret0:.
    .GetShift2ECX PROC ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
         WinABI GetAsyncKeyState,VK_SHIFT  ; Returns bit 15 of RAX set when Shift was pressed.
         XOR ECX,ECX
         SAL AX,1      ; Shift MSbit to CF.
         RCL ECX,1     ; Virtual key handlers receive RCX=1 when Shift was pressed, otherwise RCX=0.
         RET
        ENDP .GetShift2ECX
    .WM_SIZE:
         CALL WndResizeFind
         JMP .Ret0:
    .WM_KEYDOWN:                 ; Non-character hot key R8D=wParam was pressed.
         Dispatch R8D, VK_ESCAPE,VK_RETURN,VK_TAB,'C','L','F'
         JMP .Def:               ; Pass unhandled keys to WinABI DefWindowProc.
    .WM_SYSKEYDOWN:              ; A key pressed together with Alt.
         Dispatch R8D,'C','L','F',VK_RETURN,VK_ESCAPE
         JMP .Def:               ; Pass unhandled keys to WinABI DefWindowProc.
    .WM_COMMAND:               ; Window element Id=LOWORD R8 was activated.
         MOVZX EDX,R8W
         Dispatch EDX,IdBtnFind, IdBtnClear, IdBtnCancel
        JMP .Def:                ; Let other commands handle by DefWindowProc().
    .VK_TAB:
        JRCXZ .Back:
        WinABI SetFocus,[hBtnFind]
        JMP .Def:
    .L:                          ; Hotkey 'L' pressed.
    .IdBtnClear:                 ; Button Clear clicked.
        MOVW [GuiFindText],0
        WinABI SetWindowText,[hEditFind],GuiFindText
        CALL FindText
        CALL MakeIndex
        CALL WindowTitle
        JMP .Ret0:
    .Back:WinABI SetFocus,[hEditFind] ; Shift-Tab pressed inside Find dialog.Finbd
        JMP .Def:
    .VK_RETURN:                  ; Enter pressed.
    .F:                          ; Hotkey 'F' pressed.
    .IdBtnFind:                  ; Button Find clicked.
         LEA RDI,[GuiFindText]
         WinABI GetWindowTextW,[hEditFind],RDI,MAX_PATH_SIZE
         CALL FindText
         CALL WindowTitle
    .C:                          ; HotKey 'C' pressed.
    .IdBtnCancel:                ; Button Cancel clicked.
    .VK_ESCAPE:                  ; Terminate thread.
    .WM_DESTROY:                 ; Thread terminates.
         WinABI ShowWindow,[hWindowFind],SW_HIDE
    .Ret0:XOR EAX,EAX            ; RAX=0 signalizes that the message was processed here.
    .Ret:EndProcedure WndProcFind

WndResizeFind
  Dimensions of WindowFind changed.

    WndResizeFind PROC
        LEA RBX,[RectWindowMain]
        WinABI GetWindowRect,[hWindowFind],RBX
        MOV ESI,[RBX+RECT.left]
        MOV ECX,[RBX+RECT.right]
        SUB ECX,ESI
        MOV [WindowFindWidth],ECX
        MOV EDI,[RBX+RECT.top]
        MOV EDX,[RBX+RECT.bottom]
        SUB EDX,EDI
        CMP EDX,120
        JA .20:
        MOV EDX,120
    .20:WinABI MoveWindow,[hWindowFind],RSI,RDI,RCX,RDX,-1
        MOV ESI,[WindowFindWidth]; Button input file select.
        SUB ESI,3*wiBorder
        WinABI MoveWindow,[hEditFind],wiBorder,wiBorder,RSI,heTitle1,1
        SUB ESI,wiBtnIO          ; Button Find.f
        WinABI MoveWindow,[hBtnFind],RSI,yFindButton,wiBtnIO,heBtnIO,1
       RET
    ENDP WndResizeFind

LoadAndIndex
  Read, convert, index the input file.
Input
  Process the arguments ArgInputFile, ArgOutputFile, ArgInputEncoding.
Output
  Input file is mapped between [InputPtr]..[InputEnd].
  Output file is converted to UTF-16 and mapped between [InputPtrUTF16]..[InputEndUTF16],
  IndexFile is mapped between IndexPtr..IndexEnd.
Error
  Errors are reported to device context.
Called by
  MainGui

    LoadAndIndex PROC
        CALL LoadInputFile
        JC .ErrorRead:
        MOV EAX,[ArgInputEncoding::]
        TEST EAX
        JNZ .30:
        CALL AutodetectEncoding
        MOV [ArgInputEncoding::],EAX
    .30:CALL CreateOutputFile
        JC .ErrorWrite:
        CALL ConvertText                   ; Input file is loaded between [InputPtr]..[InputEnd].
        JC .ErrorWrite:                    ; Output UTF-16 stream is open in FileOutput.
        FileClose FileInput, FileOutput    ; FileOutput has now the input file converted to UTF-16.
        FileLoad  FileOutput               ; Output file is now converted to UTF-16 and memory-mapped.
        JC .ErrorReadUTF16:
        MOV [InputPtrUTF16],RSI
        MOV [InputSizeUTF16],RAX
        ADD RAX,RSI
        MOV [InputEndUTF16],RAX            ; Input file converted to UTF-16 is mapped between [InputPtrUTF16]..[InputEndUTF16].
        CALL CreateIndexFile
        JC .ErrorIndex:
        CALL WndResizeMain
        CALL MakeIndex:
        JC .ErrorIndex
        CALL InitScrollInfo
        WinABI PostMessage,[hWindowMain],WM_LBUTTONDOWN,0,0
        CALL WindowTitle
        JMP .90:
    .ErrorReadUTF16:
        LEA RBX,[FileOutput.Name]
        JMP .ER:
    .ErrorRead:
        LEA RBX,[FileInput.Name]
    .ER:Concat$ WorkingString,=U"Error reading """,RBX,=U"""",Unicode=yes
        JMP .Er:
    .ErrorIndex:
        LEA RBX,[FileIndex.Name]
        JMP .EW:
    .ErrorWrite:
        LEA RBX,[FileOutput.Name]
    .EW:Concat$ WorkingString,=U"Error writing """,RBX,=U"""",Unicode=yes
    .Er:WinABI MessageBoxW,[hWindowMain],WorkingString,0,MB_ICONEXCLAMATION
    .90:RET
       ENDP LoadAndIndex

LoadInputFile
  Open ArgInputFile and map it to memory.
Input
  ArgInputFile is the nonzero file name.
Output
  CF=0
  InputPtr, InputSize, InputEnd are pointers to the memory-mapped file.
Error
  CF=1 File not found or other error.
Called by
  LoadAndIndex

    LoadInputFile PROC
        LEA RSI,[ArgInputFile::]   ; Input file was specified. UTF-8.
        LEA RDI,[WorkingString]
        WinABI MultiByteToWideChar,65001,0,RSI,264,RDI,SIZE#WorkingString
        FileAssign FileInput,RDI, Unicode=yes
        JC .90:
        FileClose FileInput
        FileLoad FileInput
        JC .90:
        MOV [InputPtr],RSI
        MOV [InputSize],RAX
        ADD RAX,RSI
        MOV [InputEnd],RAX
    .90:RET
       ENDP LoadInputFile

CreateOutputFile
  Assign and create stream of ArgOutputFile.
Input
  ArgOutputFile is the output file name. When 0, it will be created as %TEMP%\InputFile.lst. It is stream-created.
  FileInput is assigned with InputFile name.
Output
  CF=0
  FileOutput is assigned.
Error
  CF=1 File assign|create error.
Called by
  MainGui

    CreateOutputFile PROC
        LEA RDI,[WorkingString]
        LEA RSI,[ArgOutputFile::] ; UTF-8 output name.
        CMPB [RSI],0
        JE .30:
    .10:LODSW
        CMP AL,0
        JE .20:
        STOSW
        JMP .10:
    .20:CMPW [RDI-2],'\'
        JE .50:
        MOV AX,'\'
        STOSW
        JMP .50:
    .30:WinABI GetEnvironmentVariableW,=U"TEMP",RDI,SIZE# WorkingString/2
        CMPW [RDI+2*RAX-2],'\'
        JE .40:
        MOVW [RDI+2*RAX],'\'
        INC RAX
    .40:LEA RDI,[RDI+2*RAX]
    .50:LEA RSI,[FileInput.Name]
        MOV EAX,[FileInput.NameOffs]
        ADD RSI,RAX
    .60:LODSW
        CMP AX,0
        JZ .70:
        STOSW
        JMP .60:
    .70:LEA RSI,[Ext_lst]
    .80:LODSW
        STOSW
        CMP AX,0
        JNE .80:
        FileClose FileOutput
        LEA RSI,[WorkingString]
        FileAssign FileOutput,RSI, Unicode=yes
        JC .90:
        FileMkDir FileOutput
        JC .90:
        FileStreamCreate FileOutput
    .90:RET
       ENDP CreateOutputFile

CreateIndexFile
  Assign FileIndex. FileOutput is expected to be assigned with the temporary output file name. FileIndex will be assigned with the same name, extension .lst replaced with an extension .index.
Input
  FileOutput.Name
Output
  FileIndex is assigned and stream-created. It is empty so far.
Error
  CF=1
Called by
  MainGui

    CreateIndexFile PROC
        LEA RBX,[FileIndex]
        LEA RDI,[FileOutput.Name]
        FileAssign RBX,RDI,Unicode=yes
        JC .90:
        LEA RDI,[FileIndex.Name]
        GetLength$ RDI, Unicode=yes
        ADD RDI,RCX
        SUB RDI,2*4                        ; Remove the extension .lst.
        LEA RSI,[Ext_index]                ; Replace the extension with .index.
    .40:LODSW
        STOSW
        CMP AX,0
        JNE .40:                           ; FileIndex is assigned, e.g.with C:\TEMP\InpFile.txt.index.
        FileMkDir RBX
        JC .90:
        FileClose RBX
        FileStreamCreate RBX
    .90:RET
       ENDP CreateIndexFile

MakeIndex
  Create index (LST_INDEX records) of the UTF-16 text mapped between [InputPtrUTF16] and [InputEndUTF16].
  MakeIndex is invoked whenever window size changed, font or word-wrap was pressed, but the input file was not changed.
Input
  [InputPtrUTF16]..[InputEndUTF16] is the text in UTF-16LE.
  FileIndex is an assigned unopened FILE64.
  Status:ArgWrapLines specifies whether the lines are wrapped at [Cols] (Cols is number of character in visible main window).
Output
  FileIndex is written and mapped between
  [IndexPtr]..[IndexEnd]. FileIndex remains open.
Clobbers
  RAX,RBX,RCX,RDX,RSI,RDI,R8,R9,R10

    MakeIndex PROC
        LEA RBX,[FileIndex]
        FileClose RBX
        FileStreamCreate RBX
        JC .90:
        MOV RDI,[InputPtrUTF16]  ; The UTF-16 file stays unchanged. FileIndex will be rewritten.
        MOV RCX,[InputSizeUTF16]
        MOV R9, [InputEndUTF16]
        MOV R8,RDI               ; R8..R9 is the file contents.
        MOV R10D,[Cols]          ; Screen columns in characters. Computed in WndResizeMain.
        SHR ECX,1                ; Convert input file size to characters.
    .10:CMP RDI,R9
        JAE .80:
        MOV RSI,RDI              ; Beginning of line.
        MOV AX,0x000A
        REPNE SCASW              ; Find the end of line.
    .20:MOV RAX,RSI
        SUB RAX,R8               ; File address of the line.
        FileStreamWriteDword RBX ; Write EAX=LST_INDEX.FA.
        JC .90:
        MOV RAX,RDI
        SUB RAX,RSI              ; RAX=line size in bytes.
        JNSt [Status::],ArgWrapLines,.70:
        MOV RDX,R10
        SUB EDX,4                ; Leave room for french quote.
        SHL EDX,1                ; Convert columns to bytes.
        CMP EAX,EDX              ; It the current line longer?
        JBE .70:                 ; Jump when wrap is not needed.
        LEA EAX,[EDX+FlagWrap]
        FileStreamWriteDword RBX ; Write line size + flag.
        JC .90:
        ADD ESI,EDX
        JMP .20:
    .70:FileStreamWriteDword RBX ; Write EAX=LST_INDEX.Size.
        JNC .10:
        JMP .90:
    .80 FileClose RBX
        FileLoad RBX             ; Reopen and load the index.
        JC .90:
        ADD RAX,RSI
        MOV [IndexPtr],RSI
        MOV [IndexEnd],RAX
        SUB RAX,RSI
        SHR EAX,3
        MOV [Lines],EAX
        MOVD [TopLine],1
    .90:RET
      ENDP MakeIndex

WindowTitle
  Update the title of main window to `EuroText "FileName"{row}[col], Encoding=Autodetec, nowrap, 0x found STRING`.
Input
  ArgInputFile the file name (UTF-8),
  DocRow, DocCol=row and col where clicked (position in document)
  ArgInputEncoding
  Status:ArgWrapLines,
  GuiFindText the text to find (UTF-16LE)
Called from
  WndCreateMain and WndProcMain when mouse button was clicked.

    WindowTitle PROC
        LEA RDI,[WorkingString]  ; Window title will be constructed here.
        LEA RSI,[=U' EuroText "']
        MOV ECX,11
        REP MOVSW
        LEA RSI,[ArgInputFile::]
        WinABI MultiByteToWideChar,65001,0,RSI,-1,RDI,MAX_PATH_SIZE
        LEA RDI,[RDI+2*RAX-2]
        PUSH RDI                 ; Save current position in WorkingString.
          LEA RDI,[ShortString]  ; The next part of title will be constructed as ASCII in ShortString.
          MOV AX,'"{'
          STOSW
          MOV EAX,[DocRow]
          StoD RDI
          MOV AX,'}['
          STOSW
          MOV AX,[DocCol]
          StoD RDI
          MOV EAX,'],  '
          STOSD
          MOV EAX,'Enco'
          STOSD
          MOV EAX,'ding'
          STOSD
          MOV AL,'='
          STOSB
          MOV EAX,[ArgInputEncoding::]
          TEST EAX
          JNZ .13:
          MOV EAX,'Auto'
          STOSD
          MOV EAX,'dete'
          STOSD
          MOV EAX,'ct  '
          STOSD
          JMP .18:
    .13:  PUSH RDI                         ; Store current position in ShortString.
            LEA RDI,[CPid:]
            MOV ECX,[CodePagesLength]
            MOV RSI,RDI
            REPNE SCASW                    ; Find the numeric encoding in [CPid] section.
            JNE .1F:
            SUB RDI,RSI
            SHR EDI,1
            MOV EDX,EDI                    ; 1,2,3,,,81   EDX is the ordinal number of encoding.
            LEA RDI,[CPname:]
            LEA RCX,[CPtable:]
            SUB RCX,RDI                    ; RCX is the size of section [CPname].
            XOR EAX,EAX
    .14:    DEC EDX
            JZ .15:
            REPNE SCASB
            REPNE SCASB
            JMP .14:
    .1F:    LEA RDI,[=B 0]
    .15:    MOV RSI,RDI                    ; Name of encoding was found at RDI.
          POP RDI                          ; Restore position in ShortString.
    .16:  LODSB
          TEST AL
          JZ .18:
          STOSB                            ; Copy the first name of encoding to RDI.
          JMP .16:
    .18:  LEA RSI,[=B', wrap, ']
          JSt [Status::],ArgWrapLines,.20:
          LEA RSI,[=B', nowrap, ']
    .20:  LODSB
          STOSB
          CMP AL,0
          JNE .20:
          DEC RDI
          MOV EAX,[FoundCnt]
          CMPW [GuiFindText],0
          JNE .25:
          TEST EAX
          JE .30:
    .25:  StoD
          MOV AL,0xD7                      ; Multiplication sign.
          STOSB
          MOV EAX,' fou'
          STOSD
          MOV EAX,'nd "'
          STOSD
          XOR EAX,EAX
          STOSB
    .30:POP RDI                            ; Restore position in WorkingString.
        LEA RSI,[ShortString]
        XOR EAX,EAX
    .40:LODSB
        CMP AL,0
        JE .50:
        STOSW
        JMP .40:
    .50:LEA RSI,[GuiFindText]
        CMPW [RSI],0
        JNE .60:
        MOV EAX,[FoundCnt]
        TEST EAX
        JE .80:
    .60:LODSW
        CMP AX,0
        JE .70:
        STOSW
        JMP .60:
    .70:MOV EAX,'"'
    .80:STOSD
        WinABI SetWindowTextW,[hWindowMain],WorkingString
        RET
       ENDP WindowTitle

WndFont
  Release current font [hFont] (if exists) and create a new unproportional ANSI font with [FontSize].
Input
  [FontSize] is required line height in pixels.
Output
  [hFont],[cxChar],[cyChar]

    WndFont PROC
        MOV RCX,[hFont]
        JRCXZ .10:
        WinABI DeleteObject,RCX
        MOV ECX,[FontSize]
    .10:WinABI CreateFontW, RCX, 0, 0, 0, FW_DONTCARE, 0, 0, 0, ANSI_CHARSET, \
               OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY,              \
               FIXED_PITCH | FF_SWISS, 0
        MOV [hFont],RAX
        MOV RBX,[hWindowMain]
        WinABI GetDC,RBX
        MOV RDI,RAX              ; Device context,
        WinABI SelectObject,RDI,[hFont]
        WinABI GetTextMetrics,RDI,TextMetric
        WinABI ReleaseDC,RBX,RDI
        MOV EAX,[TextMetric.tmHeight]
        MOV ECX,[TextMetric.tmAveCharWidth]
        ADD EAX,[TextMetric.tmExternalLeading]
        MOV [cxChar],ECX
        MOV [cyChar],EAX
        RET
      ENDP WndFont

AutodetectEncoding
  OS-independent procedure AutodetectEncoding reads the first 256 KB of input file, tries all encodings one after another and summarizes relevances of its characters.
  The encoding with highest sum of relevances is returned.
Input
  [InputPtr] is pointer to the start of text.
  [InputSize] is size of the data.
Output
  RAX is the autodetected encoding, e. g. 65001, 1250 etc.
  R10=relevance
Clobbers
  RCX,RDX,RSI,RDI,R8,R9,R10,R11,R12,R13

    AutodetectEncoding PROC
        MOV R8,[InputPtr]
        MOV R9,[InputSize]
        MOV R12,65001            ; UTF-8.
        CMP R9D,16
        JB .90:                  ; Shorter files cannot be autodetected.
        CMP R9D,256K
        JB .10:
        MOV R9D,256K
    .10:MOV R10,0x8000_0000_0000_0000 ; R10 is the best relevance saldo so far. R12 is its code page.
        XOR R13,R13              ; R13 is 0,1,2 corresponding with character size 1,2,4.
                                 ; Try encoding 20127 ASCII.
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
        XOR EAX,EAX
    .15:LODSB
        CMP AL,0x7F
        JA  .20:
        CALL .StoreRelevance:
        JMPS .22:
    .20:ADD R11,??               ; Any byte above 0x7F deteriorates the relevance by ??=-128.
    .22:LOOP .15:
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .30:
        MOV R12,20127
        MOV R10,R11
                                 ; Try encoding 12000 UTF-32LE.
        MOV R13B,2               ; Character size=4.
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
        SHR ECX,2
        MOV EAX,[BOM_UTF32LE]
        CMP EAX,[RSI]
        JNE .25:
        ADD R11,Bm
        ADD RSI,4
        DEC ECX
    .25:LODSD
        CALL .StoreRelevance:
        LOOP .25:
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .30:
        MOV R12,12000
        MOV R10,R11
    .30:                         ; Try encoding 12001 UTF-32BE.
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
        SHR ECX,2
        MOV EAX,[BOM_UTF32BE]
        CMP EAX,[RSI]
        JNE .35:
        ADD R11,Bm
        ADD RSI,4
        DEC ECX
    .35:LODSD
        BSWAP EAX
        CALL .StoreRelevance:
        LOOP .35:
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .40:
        MOV R12,12001
        MOV R10,R11
    .40:                         ; Try encoding 1200 UTF-16LE.
        MOV R13B,1               ; Character size=2.
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
        SHR ECX,1
        XOR EAX,EAX
        MOV AX,[BOM_UTF16LE]
        CMP AX,[RSI]
        JNE .45:
        ADD R11,Bm
        ADD RSI,2
        DEC ECX
    .45:LODSW
        CALL .StoreRelevance:
        LOOP .45:
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .50:
        MOV R12,1200
        MOV R10,R11
    .50:                         ; Try encoding 1201 UTF-16BE.
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
        SHR ECX,1
        XOR EAX,EAX
        MOV AX,[BOM_UTF16BE]
        CMP AX,[RSI]
        JNE .55:
        ADD R11,Bm
        ADD RSI,2
        DEC ECX
    .55:LODSW
        XCHG AL,AH
        CALL .StoreRelevance:
        LOOP .55:
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .60:
        MOV R12,1201
        MOV R10,R11
    .60:                         ; Try encoding 65001 UTF-8.
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
        MOV EAX,[BOM_UTF8]
        MOV EDX,[RSI]
        AND EAX,0x00FFFFFF
        AND EDX,0x00FFFFFF
        CMP EAX,EDX
        JNE .65:
        ADD R11,Bm
        ADD RSI,3
        SUB RCX,3
    .65:DecodeUTF8 RSI,.StoreRelevanceUTF8,Size=RCX,Width=32 ; Use macro from string64.htm.
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .70:
        MOV R12,65001
        MOV R10,R11
    .70:                         ; Try 8bit encoding OEM or WIDE according to CodePages 437..28606.
        XOR EDX,EDX              ; RDX is index to [CPtable].
        XOR R13,R13              ; Character size=1.
    .72:LEA RBX,[RDX+CPtable:]
        SUB R11,R11              ; R11=relevance saldo.
        MOV RSI,R8               ; Restore pointer to text from R8.
        MOV RCX,R9               ; Restore size of text from R9.
    .75:XOR EAX,EAX
        LODSB
        CMP AL,0x7F
        JBE .80:
        MOV AX,[RBX+2*RAX-256]   ; Translate AL (128..255) to unicode point in AX by this table.
    .80:CALL .StoreRelevance:    ; Add relevance of unicode point EAX to R11.
        LOOP .75:                ; The next character from the sample.
        CMP R11,R10              ; Compare with the best saldo so far in R10.
        JLE .85:                 ; Skip when poor.
        MOV R10,R11              ; R10 is the best saldo so far.
        LEA RCX,[CPid:]
        MOVZX EAX,DH
        MOVZXW R12,[RCX+2*RAX+2*6]; R12 is the best encoding so far.
    .85:INC DH                   ; Try the next encoding.
        LEA EAX,[EDX+256*6]
        CMP AH,[CodePagesLength] ; Each OEM/ANSI table is 2*128 bytes long.
        JB .72:
    .90:MOV RAX,R12              ; Autodetected encoding is returned in RAX.
        RET
    .StoreRelevanceUTF8: PROC    ; This subprocedure will add relevance of a character decoded from UTF-8
         XOR R13,R13             ;  with codepoint RAX to the saldo in R11. Clobbers: RAX,RDI,R13.
         CMP EAX,80h
         JB .4:
         INC R13
         CMP EAX,800h
         JB .4:
         INC R13
      .4:                        ; Continue with .StoreRelevance:.  R13=0,1,2.
       ENDP .StoreRelevanceUTF8:
    .StoreRelevance: PROC        ; This subprocedure will add relevance of a character
        PUSH RCX,RSI             ;  with codepoint EAX to the saldo in R11. Clobbers: RAX,RDI.
         XOR ESI,ESI
         CMP EAX,0x0000_FFFF
         JA .9:                  ; Characters above BMP (asian, emojis) do not influence the relevance.
         LEA RDI,[CodePoint]
         LEA RSI,[RDI+2]
         MOV ECX,[CodePointLength]
         REPNE SCASW
         JE .6:
         MOV RSI,??              ; Deteriorate the relevance when this character is not in our Unicode table.
         JMP .8:
    .6:  SUB RDI,RSI             ; Otherwise find the corresponding relevance.
         LEA RSI,[Relevance:]
         SHR RDI,1
         MOVSXB RSI,[RSI+RDI]
    .8:  MOV RCX,R13
         SAL RSI,CL              ; Double (UTF-16) or quadruple (UTF-32) the relevance.
         ADD R11,RSI             ; Add it to the saldo R11.
    .9: POP RSI,RCX
        CLC
        RET
       ENDP .StoreRelevance:
     ENDP AutodetectEncoding

ConvertText

  ConvertText expects that input file is mapped between [InputPtr]..[InputEnd], its encoding is specified in ArgInputEncoding:: (not zero), and FileOutput is assigned and open for stream write. This procedure will read the input, convert encoding of each character to UTF-16LE and write the converted contents of register AX to FileOutput.

Input
  [InputPtr]..[InputEnd] is contents of the input file. FileOutput is open.
  ArgInputEncoding::] is encoding of InputFile.
Output
  CF=0 FileOutput is written.
Error
  CF=1 on error write to FileOutput.
Called by
  MainGui

    ConvertText  PROC
        LEA RBX,[FileOutput]
        MOV RSI,[InputPtr]
        MOV RDX,[InputEnd]
        MOV EAX,[ArgInputEncoding::]
        RstSt [Status::],ArgBigEndian
        Dispatch AX,20127,65001,1200,1201,12000,12001 ; Dispatch to ASCII or UTF input encodings.
        ; Other 8bit input encodings need to translate by the TranslationTable in RCX.
        LEA RDI,[CPid:]
        MOV RSI,RDI
        MOV ECX,[CodePagesLength]
        REPNE SCASW
        JNE .Error:
        SUB RDI,RSI
        SUB RDI,2*7
        JB .Error:
        LEA RSI,[CPtable:]
        SHL EDI,7
        LEA RCX,[RSI+RDI]        ; RCX=pointer to translation table (128 words).
        MOV RSI,[InputPtr]
        MOV RDX,[InputEnd]
    .20:CMP RSI,RDX
        JNB .90:
        MOVZXB EAX,[RSI]
        CMP AL,0x80
        JB .25:
        MOVZXW EAX,[RCX+2*RAX-256]
    .25:FileStreamWriteWord RBX
        JC .Error:
        INC RSI
        JMP .20:
    .20127:                      ; ASCII
        XOR EAX,EAX
    .30:CMP RSI,RDX
        JNB .90:
        LODSB
        FileStreamWriteWord RBX
        JC .Error:
        JMP .30:
    .12001:                      ; UTF-32BE
        SetSt [Status::],ArgBigEndian
    .12000:                      ; UTF-32LE
        CMP RSI,RDX
        JNB .90:
        LODSD
        JNSt [Status::],ArgBigEndian,.35:
        BSWAP EAX
    .35:TEST EAX,0xFFFF_0000
        JZ .40:
        SUB EAX,0x0001_0000
        PUSH RAX
         SHR EAX,10
         AND EAX,0x0000_03FF
         ADD EAX,0x0000_D800
         FileStreamWriteWord RBX ; High surrogate.
        POP RAX
        AND EAX,0x0000_03FF
        ADD ECX,0x0000_DC00
    .40:FileStreamWriteWord RBX  ; Low surrogate or ordinary character.
        JC .Error:
        JMP .12000:
    .1201:                       ; UTF-16BE
        SetSt [Status::],ArgBigEndian
    .1200:                       ; UTF-16LE
        CMP RSI,RDX
        JNB .90:
        XOR EAX,EAX
        LODSW
        JNSt [Status::],ArgBigEndian,.45:
        XCHG AL,AH
    .45:FileStreamWriteWord RBX
        JC .Error:
        JMP .1200:
    .65001:                      ; UTF-8
        MOV RCX,RDX
        SUB RCX,RSI
        DecodeUTF8 RSI,.StoreWord,Size=RCX,Width=16
        CLC
        JMP .90:
    .StoreWord:
        FileStreamWriteWord FileOutput
        JNC .90:
    .Error:
        STC
    .90:RET
      ENDP ConvertText

FindText
  Search the `GuiFindText` in OutputFile. When found, it marks LST_INDEX.Size of its line with FlagFound.
Input
  GuiFindText the searched text (needle) in UTF-16LE.
  InputPtrUTF16..InputEndUTF16 haystack in UTF-16LE.
  IndexPtr..IndexEnd Indexes of output text as LST_INDEX.
Output
  [FoundCnt]= how many time was the needle found.
  LST_INDEX.Size:FlagFound is set for lines which contain GuiFindText.
Clobbers
  R8=InputPtrUTF16
  R9W=First character of GuiFindText - the needle (UTF-16).
  R10=Size of the rest of GuiFindText in chars - the needle (0,1,2,,)
  R11=Pointer to the rest of needle - GuiFindText+2
  R12,R13,R14=cache for RCX,RSI,RDI
Called from
  WndProcFind.

    FindText PROC
        XOR EDX,EDX                        ; Counter.
        LEA RDI,[GuiFindText]              ; Get the size of searched needle.
        CMPW [RDI],0
        JE .80:
        LEA R11,[RDI+2]
        MOV R9,[RDI]
        XOR EAX,EAX
        MOV ECX,MAX_PATH_SIZE
        REPNE SCASW
        SUB RDI,R11
        SHR EDI,1                           ; Convert bytes to characters.
        MOV [FindTextLength],EDI
        JZ .10:
        DEC EDI
    .10:MOV R10,RDI                        ; Length of needle-1.
        MOV R8,[InputPtrUTF16]
        MOV RSI,[IndexPtr::]
        SUB RSI,SIZE# LST_INDEX
    .30:ADD RSI,SIZE# LST_INDEX            ; Loop through all indexed lines.
        CMP RSI,[IndexEnd::]
        JAE .80:
        MOV ECX,[RSI+LST_INDEX.Size]
        AND ECX,~FlagFound                 ; Reset FlagFound which might have been set from previous search.
        MOV [RSI+LST_INDEX.Size],ECX
        CMP R9W,0                          ; Nothing to search?
        JZ .30:                            ; Continue to erase FlagFound from all lines.
        AND ECX,NoFlags                    ; ECX is line size in bytes.
        SHR ECX,1                          ; ECX is line size in unichars.
        MOV AX,R9W                         ; The first character of the needle.
        MOV EDI,[RSI+LST_INDEX.FA]
        ADD RDI,R8
    .50:REPNE SCASW                        ; Find the first character.
        JNE .30:
        MOV R12,RCX
        MOV R13,RSI
        MOV R14,RDI
         MOV RCX,R10
         MOV RSI,R11
         REPE CMPSW                        ; Compare the rest.
        MOV RDI,R14
        MOV RSI,R13
        MOV RCX,R12
        JNE .50:                           ; If no match found, continue to search the first character.
        ORD [RSI+LST_INDEX.Size],FlagFound ; Set the FlagFound.
        INC EDX
        JMP .30:
    .80:MOV [FoundCnt],EDX
        MOV [LineFound],1
        TEST EDX
        JNZ .90:
        MOV [LineFound],EDX
    .90:RET
      ENDP FindText

Copy2Clipboard
  Copy the text from [DocRowStart],[DocColStart]..[DocRowStop],[DocColStop] to clipboard.

    Copy2Clipboard PROC
         MOV EDI,[DocRowStart]
         DEC EDI
         SHL EDI,3
         ADD RDI,[IndexPtr]
         MOV ESI,[RDI+LST_INDEX.FA]        ; FA in bytes.
         MOV EAX,[DocColStart]             ; Column in characters.
         LEA ESI,[ESI+2*EAX-2]
         ADD RSI,[InputPtrUTF16]           ; Pointer to 1st unichar of the clipboard.
         MOV EDI,[DocRowStop]
         DEC EDI
         SHL EDI,3
         ADD RDI,[IndexPtr]
         MOV EBX,[RDI+LST_INDEX.FA]
         MOV EAX,[DocColStop]
         LEA EBX,[EBX+2*EAX]
         ADD EBX,[InputPtrUTF16]             ; RSI..RBX is the clipboard contents.
         MOV RCX,[InputEndUTF16]
         CMP RSI,RCX
         JA .90:
         CMP RBX,RCX
         JNA .70:
         MOV RBX,RCX
    .70: MOV R12,RBX
         SUB R12,RSI
         ADD R12,2
         WinABI GlobalAlloc,GMEM_FIXED|GMEM_SHARE,R12
         TEST RAX
         JZ .90:
         MOV R13,RAX
         WinABI GlobalLock,RAX
         MOV RDI,RAX
         MOV RCX,R12
         REP MOVSB
         WinABI GlobalUnlock,R13
         WinABI OpenClipboard,[hWindowMain]
         WinABI EmptyClipboard
         WinABI SetClipboardData,CF_UNICODETEXT,R13
         WinABI CloseClipboard
    .90: RET
     ENDP Copy2Clipboard

InitScrollInfo
  Initialize ScrollInfo structure.

    InitScrollInfo PROC
        MOV [ScrollInfo.cbSize], SIZE# SCROLLINFO
        MOV [ScrollInfo.fMask], SIF_RANGE | SIF_PAGE
        MOV [ScrollInfo.nMin],1
        WinABI SetScrollInfo, [hWindowMain],SB_VERT,ScrollInfo,1
        RET
     ENDP InitScrollInfo

ReadFileIni
  Procedure ReadFileIni reads lines from FileIni in UTF-8 and parses its each line into configuration variables Arg*** in UTF-8, too.
  The FileIni.Name is in UTF-16. Procedure writes information about the file name and whether it was found.
Input
  FileIni is assigned with the name.
Clobbers
  RAX,RCX,RDX,RSI,RDI

    ReadFileIni PROC
        SetSt [Status::],ArgFromFile       ; Tell ArgParse that arguments may not begin with / or -.
        ;; StdOutput =U'Configuration "',FileIni.Name,Console=yes,Unicode=yes
    .10:FileStreamOpen FileIni,BufSize=4K
        JNC .20:
        ;; StdOutput =B'" was not found.',Eol=yes,Unicode=no
        JMP .90:
    .20:FileStreamReadLn FileIni
        JBE .80:
        MOV ECX,EAX
        ; The first line may begin with BOM.
        MOV AX,[RSI]
        CMPW AX,0xBBEF   ; UTF-8 BOM?
        JNE .50:
        ADD RSI,3        ; Skip the BOM.
        SUB ECX,3
        JB .80:
        JMP .50:
    .30:FileStreamReadLn FileIni
        JBE .80:
        MOV ECX,EAX
    .50:CALL ArgParse::
        JNC .30:
        FileClose FileIni
        TerminateProgram 8
    .80:FileClose FileIni
    .90:RstSt [Status::],ArgFromFile
        RET
      ENDP ReadFileIni

     ENDPROGRAM textwing

▲Back to the top▲