EuroAssembler Index Manual Download Source Macros


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▲