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
[.rodata] segment.
[CodePoint] (WORD) and [Relevance] (BYTE).
[Translit] (DWORD) and [Entity] (QWORD) are not used in EuroText program.
[.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.
"ISO-8859-2";
"Latin 2 (Central European)";
https://en.wikipedia.org/wiki/Windows-1250 (not used in this program);
[CPid].
[CPname] one after another..
[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.
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.
[.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 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
[%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.
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 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
TopLine variable.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
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 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 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 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 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 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 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 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 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
.lstreplaced with an extension
.index.
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 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
EuroText "FileName"{row}[col], Encoding=Autodetec, nowrap, 0x found STRING.
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 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 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 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.
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
GuiFindText in OutputFile. When found, it marks LST_INDEX.Size of its line with FlagFound.
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 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 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 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