Author Topic: my editor project  (Read 10702 times)

jj2007

  • Member
  • *****
  • Posts: 13958
  • Assembly is fun ;-)
    • MasmBasic
Re: my editor project
« Reply #105 on: October 12, 2022, 11:07:00 AM »
I never use "USES". So I have a pretty good idea of what's going on "under the hood" with my subroutines.

Me too, but in WndProc with more than a dozen message handlers I certainly have a uses esi edi ebx on top. 6 bytes, about 3 cycles, in a proc whose handlers typically take several thousand cycles. The fastest one is probably WM_MOUSEMOVE, and even that one doesn't really get disturbed by three pushes & pops. No clutter, just one ret instruction directly under the invoke DefWindowProc. It's a matter of taste, of course, but I don't want to be bothered by counting the pushs and pops :cool:

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #106 on: October 12, 2022, 12:01:02 PM »
Yes, I do like Zedd.
well, I like you too.  :joking:
Regards, zedd.
:tongue:

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #107 on: October 13, 2022, 02:37:28 AM »
Well, I took a day long excursion into the world of 64 bit assembly programming. And I'm back already. While writing code for 64 bit may have its merits, the time it takes to convert some code from 32 -> 64, or write new code that is 100% 64 bit - outweighs any merits that it may have. For me at least. Still a steep learning curve involved with it for me. Hell, I barely grasp some concepts in 32 bit.  :toothy:

Therefore I am going to resume where I had left off here.  :biggrin:  I will still play with 64 bit code from time to time, it's just not my cup o' coffee.  :tongue:  I had also decided to scrap the 32 bit windows 7 partition and keep using the 64 bit flavor of the OS. Before this I had 32 bit Windows 7 exclusively and reinstalled 64 only when the need for it arose.

I am looking right now at making the code here more 'presentable'. I don't really like some parts of it, even though it 'works'. So, I'm looking at revising some of it before continuing to add some missing functionality.  :cool: 

Another thing I have been looking into is creating the Menu in code, rather than using a resource for it, also dialog boxes. NoCferMe suggested that for dialog boxes, but I recalled some code for menus as well. I will look into it, but may not make it into this project but we will see how involved it is. Might just be easier to use resources.
« Last Edit: October 13, 2022, 05:31:50 AM by zedd151 »
Regards, zedd.
:tongue:

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #108 on: October 13, 2022, 04:52:00 AM »
Cleaned up some unused code, removed redundant tab replacement code from the richedits WNDPROC (already handled in message pump). Added some sparse commenting. Most of the code is usual stuff anyway.  :tongue:
I had rethought the idea of making the menus and dialog boxes in code. Much simpler to use resed to create both.  :wink2:


Attachment 'basic editor13.zip' removed but is included in the archive In this post
« Last Edit: November 17, 2022, 12:43:58 PM by zedd151 »
Regards, zedd.
:tongue:

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project - search and replace
« Reply #109 on: October 13, 2022, 07:34:21 AM »
I have finally put in the search and replace code. Downconverted from 64 bit code.  :azn:
Using the updated 'TextFind' code posted by hutch in version 3 of tEdit  attachment (64 bit code); which allows for searching upward for single characters.

Now it is a full fledged editor with the features anyone would expect from an editor of this type, plus sorting functions.  :biggrin:   Nice clean interface, no toolbar, no tooltips, no eye candy.
More custom functions are coming very soon, mostly functions that I find very useful for formatting code.

I have disabled the 'replace text' function. Will replace that code and update the attachment shortly.
Seems hutch coded the text replace function in tEdit to search for the text first then replace that instance of it, if needed to replace multiple instances, would need to keep searching up/down for next occurrence to replace. So will revise another "text replace" function to work with the resource ID's used here. Temporarily removed attachment...
Will reattach file when I have the normal text replace function ready. (will be able to replace all instances of text in selection)


Attachment 'basic editor14.zip' removed but is included in the archive In this post
« Last Edit: November 17, 2022, 12:44:25 PM by zedd151 »
Regards, zedd.
:tongue:

jj2007

  • Member
  • *****
  • Posts: 13958
  • Assembly is fun ;-)
    • MasmBasic
Re: my editor project - search and replace
« Reply #110 on: October 13, 2022, 08:23:45 AM »
searching upward for single characters.

When would you need that, can you give an example?

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #111 on: October 13, 2022, 08:27:43 AM »
Not necessarily for code mind you, I did need it at one point for searching for occurrences of a single character. It does come up at times.  :biggrin:    If you're going to have a search function, why not do it properly?  :tongue:  So, does RichMasm limit searches to two characters or more? Have you never used single character variables? As an example I often use local variables x,y,w,h also as arguments at times.  :azn:  Reduces the code there.  :biggrin:
Regards, zedd.
:tongue:

jj2007

  • Member
  • *****
  • Posts: 13958
  • Assembly is fun ;-)
    • MasmBasic
Re: my editor project
« Reply #112 on: October 13, 2022, 11:12:38 AM »
So, does RichMasm limit searches to two characters or more?

No, see below.

Quote
Have you never used single character variables?

If I remember well, my Zx Spectrum allowed only single character variables in its BASIC. So, yes, I once did use them.

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #113 on: October 13, 2022, 12:38:24 PM »
So, does RichMasm limit searches to two characters or more?
No...
Ok, so that should answer your question about needing to search for single characters. Because its the right thing to do if you want the search function to work properly.  :biggrin:
Regards, zedd.
:tongue:

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #114 on: October 13, 2022, 01:55:10 PM »
Now regarding my post #109 here, I have text replace code that is old code and combined with text find code. I had once an editor that used the same dialog box for handling both functions. I will *try* to separate out the text replace part of it, as the current find text function works perfectly. I could write a new function from scratch, but that will take a little longer.... let me try to salvage the old code first, and change the control ID's and variables first though...  :biggrin:  it's gonna be phun
Regards, zedd.
:tongue:

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: my editor project
« Reply #115 on: October 13, 2022, 02:04:07 PM »
Well, if it helps, here's the find text code from my editor (also RichEdit based):

Code: [Select]
;====================================
; Find that text!
;====================================

do_find:
; Get the direction & case-sensitivity settings:
INVOKE IsDlgButtonChecked, hWin, $upRadio
MOV DL, FALSE
CMP EAX, BST_CHECKED
JE @F
MOV DL, TRUE
@@: MOV FindDirDown, DL

; Set case sensitivity flag to checkbox setting:
INVOKE IsDlgButtonChecked, hWin, $caseChk
MOV DL, TRUE
CMP EAX, BST_CHECKED
JE @F
MOV DL, FALSE
@@: MOV FindCaseSensitive, DL

; Get the text to find:
INVOKE GetDlgItemText, hWin, $findEdit, OFFSET FindTextBuffer, SIZEOF FindTextBuffer

; Are we finding up or down?
CMP FindDirDown, FALSE
JE findUp

; See if there's anything to find:
CMP FindTextBuffer[0], NULL
JE focus

; Get the selection from the edit control, if there is one:
INVOKE SendMessage, EditHandle, EM_GETSEL, ADDR startSel, ADDR endSel
MOV EAX, startSel
CMP EAX, endSel
JNE fsel

;If end sel. = start sel., no selection, so start at startSel
MOV EAX, startSel
JMP SHORT fsel1

; Since there's a selection, start from its end:
fsel: MOV EAX, endSel
fsel1: MOV ft.chrg.cpMin, EAX
MOV ft.chrg.cpMax, -1
MOV ft.lpstrText, OFFSET FindTextBuffer

; Set case sensitivity according to current flag setting:
MOV EDX, FR_DOWN
CMP FindCaseSensitive, TRUE
JNE @F
OR EDX, FR_MATCHCASE

; Returns -1 if nothing found, index of 1st char. of search text if found.
@@: INVOKE SendMessage, EditHandle, EM_FINDTEXTEX, EDX, ADDR ft
CMP EAX, -1
JNE @F
INVOKE wsprintf, ADDR buffer, OFFSET FindTextFmt, OFFSET FindTextBuffer, OFFSET NotFoundStr
INVOKE SendMessage, StatusHandle, SB_SETTEXT, 1, ADDR buffer
JMP focus

@@: MOV startSel, EAX
MOV EAX, OFFSET FindTextBuffer
CALL strlen
ADD EAX, startSel
INVOKE SendMessage, EditHandle, EM_SETSEL, startSel, EAX
INVOKE SendMessage, EditHandle, EM_HIDESELECTION, 0, 0
INVOKE SendMessage, StatusHandle, SB_SETTEXT, 1, ADDR DummyText
JMP focus


;===================================
; Find text (up):
;===================================

findUp:
; Get the selection from the edit control, if there is one:
INVOKE SendMessage, EditHandle, EM_GETSEL, ADDR startSel, ADDR endSel
MOV EAX, startSel
TEST EAX, EAX ;Already @ start?
JZ @F
DEC EAX ;  No, so back up 1.
@@: MOV ft.chrg.cpMin, EAX
MOV ft.chrg.cpMax, 0 ;Is this ignored for this op? YES.
MOV ft.lpstrText, OFFSET FindTextBuffer

; Set case sensitivity according to current flag setting:
XOR EDX, EDX
CMP FindCaseSensitive, TRUE
JNE @F
OR EDX, FR_MATCHCASE

; Returns -1 if nothing found, index of 1st char. of search text if found.
@@: INVOKE SendMessage, EditHandle, EM_FINDTEXTEX, EDX, ADDR ft
CMP EAX, -1
JNE @F
INVOKE wsprintf, ADDR buffer, OFFSET FindTextFmt, OFFSET FindTextBuffer, OFFSET NotFoundStr
INVOKE SendMessage, StatusHandle, SB_SETTEXT, 1, ADDR buffer
JMP focus

@@: MOV startSel, EAX
MOV EAX, OFFSET FindTextBuffer
CALL strlen
ADD EAX, startSel
INVOKE SendMessage, EditHandle, EM_SETSEL, startSel, EAX
INVOKE SendMessage, EditHandle, EM_HIDESELECTION, 0, 0
INVOKE SendMessage, StatusHandle, SB_SETTEXT, 1, ADDR DummyText
JMP focus

Most of this is just a wrapper for the EM_FINDTEXTEX message which does the actual heavy lifting here. The code checks the settings of the direction radio buttons (up/down) and the case-sensitivity checkbox (which just sets the FR_MATCHCASE flag if the user wants case sensitivity). Not much else going on here. Notice that there are two branches, since searching up instead of down involves a different dance to go backwards instead of forwards to find the next match.

The "focus" label sets the focus back to the edit control so you don't have to do an extra (and annoying!) mouse click once the dialog is closed to resume editing.

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #116 on: October 13, 2022, 02:09:58 PM »
No, no. I have that code and it works fine. It's the text replace I am working on now. The one that I had gotten from Masm64 SDK examples does a one time replacement only, you'd have to search for next occurrence then click replace again, for each occurrence of text needed to be replaced. My old code replaced all occurrences in a selected portion of text with one button press. The way it should be. Once I have the replace text function up and running, I'll post it of course...  :biggrin:
Regards, zedd.
:tongue:

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: my editor project
« Reply #117 on: October 13, 2022, 02:21:39 PM »
Wellll, you ought to give the user the choice of replacing the next match (and the next and the next and the next ...) or replacing everything. Lots of times you don't want to replace all occurrences.

Replacing text this way is a bit trickier (replacing all is easy peasy, just loop until you find no more matches). I ended up setting a flag, ReplaceStarted, that was needed in order to go back through the code AFTER doing a replacement, finding the next occurrence of the text to be replaced, then waiting for the user to click "OK" to replace that occurrence, etc.

Here's how I defined the behavior of replacing text:

;====================================
; Find/replace behavior:
; When first initiated, Replace does a find (in the current direction)
; of the "find" text. Afterwards, Replace will replace the next instance
; of that text found, after which it finds the *next* occurrence.
; It will repeat this sequence until the dialog is closed, or until no
; more find text is found.
;====================================


(basically the same as Notepad, which has a pretty rational scheme.)

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project
« Reply #118 on: October 13, 2022, 02:45:07 PM »
Yes of course. I know the basics involved. Also, first see if 'whole word' and 'same case' are checked and proceed accordingly... ladeedaaa... Lemme get back to the code
As far as choice, just select the portion of text where you want the text replaced, or select all.  :biggrin:
Regards, zedd.
:tongue:

zedd151

  • Member
  • *****
  • Posts: 1968
Re: my editor project new search & replace
« Reply #119 on: October 13, 2022, 04:53:07 PM »
I found out two things. First: The find text function in the old code works fine. Second: It was easier to use the old dialog box and control IDs rather than changing them. I now have working Search AND Replace. As a bonus, the source also had "Go to Line Number" in the same file. (Same dialog box. Dunno why I did that, I dont remember)
Code: [Select]
        SearchReplace   proto :dword, :dword, :dword, :dword
        TextFindDown    proto :dword, :dword
        TextFindUp      proto :dword, :dword
        ReplText        proto :dword, :dword
        strrepI         proto :dword, :dword, :dword, :dword
        zstrlenz        proto :dword
        zstrcpyz        proto :dword, :dword
        strcmpI         proto :dword, :dword
        zstrclrz        proto :dword


    .data
        CaseFlag        dd ?
        WholeWord       dd ?
        hCaseChk        dd ?
        hWordChk        dd ?
        hFindText       dd ?
        SearchText      dd ?
        ReplaceTxt      db 128 dup (0)
        hReplText       dd ?
        hGotoText       dd ?
       
    .code
    SearchReplace proc hWin:dword, uMsg:dword, wParam:dword, lParam:dword
    local textlen:dword, lineno:dword, cr:CHARRANGE
    .if uMsg == WM_INITDIALOG
      invoke GetDlgItem, hWin, 801
      mov hCaseChk, eax
      invoke GetDlgItem, hWin, 802
      mov hWordChk, eax
      invoke GetDlgItem, hWin, 803
      mov hFindText, eax
      invoke GetDlgItem, hWin, 806
      mov hReplText, eax
      invoke GetDlgItem, hWin, 808
      mov hGotoText, eax
    .elseif uMsg == WM_COMMAND


    .if wParam == 804
        invoke SendMessage, hFindText, WM_GETTEXTLENGTH, 0, 0
        mov textlen, eax
        cmp eax, 0
        jnz @f
        return 0
    @@:
        invoke SendMessage, hCaseChk, BM_GETCHECK, 0, 0
        cmp eax, BST_CHECKED
        jnz @f
        mov CaseFlag, 1
        jmp getwordy
    @@:
        mov CaseFlag, 0
    getwordy:
        invoke SendMessage, hWordChk, BM_GETCHECK, 0, 0
        cmp eax, BST_CHECKED
        jnz @f
        mov WholeWord, 1
        jmp getlenthy
    @@:
        mov WholeWord, 0
    getlenthy:
        inc textlen
        invoke SendMessage, hFindText, WM_GETTEXT, textlen, addr SearchText
        invoke TextFindUp, addr SearchText, textlen
        invoke SetFocus, hEdit
        xor eax, eax
        ret


    .elseif wParam == 805
        invoke SendMessage, hFindText, WM_GETTEXTLENGTH, 0, 0
        mov textlen, eax
        cmp eax, 0
        jnz @f
        return 0
    @@:
        invoke SendMessage, hCaseChk, BM_GETCHECK, 0, 0
        cmp eax, BST_CHECKED
        jnz @f
        mov CaseFlag, 1
        jmp getwordv
    @@:
        mov CaseFlag, 0
    getwordv:
        invoke SendMessage, hWordChk, BM_GETCHECK, 0, 0
        cmp eax, BST_CHECKED
        jnz @f
        mov WholeWord, 1
        jmp getlenthv
    @@:
        mov WholeWord, 0
    getlenthv:
        inc textlen
        invoke SendMessage, hFindText, WM_GETTEXT, textlen, addr SearchText
        invoke TextFindDown, addr SearchText, textlen
        invoke SetFocus, hEdit
        xor eax, eax
        ret


    .elseif wParam == 807
        invoke SendMessage, hFindText, WM_GETTEXTLENGTH, 0, 0
        mov textlen, eax
        cmp eax, 0
        jnz @f
        return 0
    @@:
        invoke GetWindowText, hFindText, addr SearchText, 128
        invoke GetWindowText, hReplText, addr ReplaceTxt, 128
        invoke ReplText, addr SearchText, addr ReplaceTxt
        invoke SetFocus, hEdit


    .elseif wParam == 809
        invoke GetDlgItemInt, hWin, 808, 0, FALSE
        mov lineno, eax
        dec lineno
        invoke SendMessage, hEdit, EM_LINEINDEX, lineno, 0
        mov cr.cpMin, eax
        mov cr.cpMax, eax
        invoke SendMessage, hEdit, EM_LINELENGTH, cr.cpMin, 0
        add cr.cpMax, eax
        invoke SendMessage, hEdit, EM_EXSETSEL, 0, addr cr
        invoke EndDialog, hWin, 0
    .endif
    .elseif uMsg == WM_CLOSE
      invoke EndDialog, hWin, 0
    .endif
        xor eax, eax
        ret
    SearchReplace endp


    ReplText proc txtfind:dword, txtrepl:dword
    local tmpbuf:dword, Cr:CHARRANGE, tmpsize:dword, selsize:dword
    local tmpbuf2:dword, plugin:dword
   
        invoke SendMessage, hCaseChk, BM_GETCHECK, 0, 0
        cmp eax, BST_CHECKED
        jnz @f
        mov CaseFlag, 1
        jmp x5
      @@:
        mov CaseFlag, 0
      x5:
        invoke SendMessage, hWordChk, BM_GETCHECK, 0, 0
        cmp eax, BST_CHECKED
        jnz @f
        mov WholeWord, 1
        jmp x6
      @@:
        mov WholeWord, 0
      x6:
        invoke SendMessage, hEdit, EM_EXGETSEL, 0, addr Cr
        mov eax, Cr.cpMin
        mov edx, Cr.cpMax
        sub edx, eax
        jz done
        mov selsize, edx
        shl edx, 3
        mov tmpsize, edx
        invoke GlobalAlloc, GPTR, tmpsize
        mov tmpbuf, eax
        invoke GlobalAlloc, GPTR, tmpsize
        mov tmpbuf2, eax
        invoke SendMessage, hEdit, EM_GETSELTEXT, 0, tmpbuf
       
        invoke strrepI, tmpbuf, tmpbuf2, txtfind, txtrepl
       
        invoke zstrlenz, tmpbuf2
        cmp eax, 0
        jz @f
        invoke zstrcpyz, tmpbuf, tmpbuf2
    @@:
        invoke SendMessage, hEdit, EM_REPLACESEL, TRUE, tmpbuf
        invoke zstrlenz, tmpbuf
        mov tmpsize, eax
        mov eax, Cr.cpMin
        add eax, tmpsize
        mov Cr.cpMax, eax
        invoke SendMessage, hEdit, EM_EXSETSEL, 0, addr Cr
        invoke GlobalFree, tmpbuf
        invoke GlobalFree, tmpbuf2
    done:
        ret
    ReplText endp


    TextFindDown proc lpBuffer:dword, Len:dword
    local tp:dword, tl:dword, sch:dword, ft:FINDTEXT, Cr:CHARRANGE
        invoke SendMessage, hEdit, WM_GETTEXTLENGTH, 0, 0
        mov tl, eax
        invoke SendMessage, hEdit, EM_EXGETSEL, 0, addr Cr
        inc Cr.cpMin
        mrm ft.chrg.cpMin, Cr.cpMin
        mrm ft.chrg.cpMax, tl
        mrm ft.lpstrText, lpBuffer
        mov sch, FR_DOWN


    .if CaseFlag == 1
        or sch, FR_MATCHCASE
    .endif


    .if WholeWord == 1
        or sch, FR_WHOLEWORD
    .endif
        invoke SendMessage, hEdit, EM_FINDTEXT, sch, addr ft
        mov tp, eax


    .if tp == -1
        szText nomatch, "No further matches"
        invoke MessageBox, hWnd, addr nomatch, 0, MB_OK
        ret
    .endif
        mrm Cr.cpMin, tp
        dec Len
        mov eax, Len
        add tp, eax
        mrm Cr.cpMax, tp
        invoke SendMessage, hEdit, EM_EXSETSEL, 0, addr Cr
        ret
    TextFindDown endp


    TextFindUp proc lpBuffer:dword, Len:dword
    local tp:dword, tl:dword, sch:dword, ft:FINDTEXT, Cr:CHARRANGE
        invoke SendMessage, hEdit, WM_GETTEXTLENGTH, 0, 0
        mov tl, eax
        invoke SendMessage, hEdit, EM_EXGETSEL, 0, addr Cr
        mrm ft.chrg.cpMin, Cr.cpMin
        mrm ft.chrg.cpMax, tl
        mrm ft.lpstrText, lpBuffer
        mov sch, 0


    .if CaseFlag == 1
        or sch, FR_MATCHCASE
    .endif


    .if WholeWord == 1
        or sch, FR_WHOLEWORD
    .endif
        invoke SendMessage, hEdit, EM_FINDTEXT, sch, addr ft
        mov tp, eax


    .if tp == -1
        invoke MessageBox, hWnd, addr nomatch, 0, MB_OK
        ret
    .endif
        mrm Cr.cpMin, tp
        dec Len
        mov eax, Len
        add tp, eax
        mrm Cr.cpMax, tp
        invoke SendMessage, hEdit, EM_EXSETSEL, 0, addr Cr
        ret
    TextFindUp endp


    strrepI proc src:dword, dst:dword, fStr:dword, rStr:dword
    local fLen:dword
        push esi
        push edx
        push edi
        push ecx
        push ebx
        xor eax, eax
        mov ecx, fStr
        nops 8
        @@:
        cmp byte ptr [ecx+eax], 0
        jz @f
        inc eax
        jmp @b
        @@:
       
        mov fLen, eax
        mov esi, src
        mov edi, dst
        mov ebx, fStr
      top:
        mov al, byte ptr [esi]
        cmp al, 0
        jz done
        invoke strcmpI, esi, ebx
        cmp al, 0
        jnz nomatchz


    .if WholeWord == 1
        xor eax, eax
        mov al, byte ptr [esi-1]
        lea ecx, namebytetable
        mov al, [ecx+eax]
        cmp al, 0
        jnz nomatchz
        mov eax, fLen
        mov al, byte ptr [esi+eax]
        lea ecx, namebytetable
        mov al, [ecx+eax]
        cmp al, 0
        jnz nomatchz
       
    .endif
   
        add esi, fLen
        mov edx, rStr
      cpyit:
        mov al, byte ptr [edx]
        cmp al, 0
        jz top
        mov byte ptr [edi], al
        inc edi
        inc edx
        jmp cpyit
      nomatchz:
        mov al, byte ptr [esi]
        cmp al, 0
        jz done
        mov byte ptr [edi], al
        inc esi
        inc edi
        jmp top
      done:
        mov byte ptr [edi], 0
        pop ebx
        pop ecx
        pop edi
        pop edx
        pop esi
        ret
    strrepI endp




    option prologue:none
    option epilogue:none
    strcmpI proc src:dword, fnd:dword
        push ecx
        push edx
        xor eax, eax
        mov ecx, [esp+12]
        mov edx, [esp+16]
        topx:
        mov al, [ecx]
        cmp al, 0
        jz donex
        .if CaseFlag == 0
        call lowbite
        .endif
        mov ah, al
        mov al, [edx]
        .if CaseFlag == 0
        call lowbite
        .endif
        cmp al, ah
        jnz outt
        inc ecx
        inc edx
        jmp topx
        donex:
        xor eax, eax
        outt:
        pop edx
        pop ecx
        ret 8
    strcmpI endp
    option prologue:prologuedef
    option epilogue:epiloguedef


    option prologue:none
    option epilogue:none
    lowbite proc
        cmp al, "A"
        jl @f
        cmp al, "Z"
        jg @f
        add al, 20h
        @@:
        ret
    lowbite endp
    option prologue:prologuedef
    option epilogue:epiloguedef


    zstrcpyz proc dst:dword, subs:dword
        push esi
        push edi
        mov esi, subs
        mov edi, dst
        xor eax, eax
        @@:
        mov al, [esi]
        cmp al, 0
        jz @f
        mov [edi], al
        inc esi
        inc edi
        jmp @b
        @@:
        invoke zstrclrz, edi
        mov eax, dst
        pop edi
        pop esi
        ret
    zstrcpyz endp


    zstrclrz proc src:dword
        mov eax, src
        push eax
        @@:
        cmp byte ptr [eax], 0
        jz @f
        mov byte ptr [eax], 0
        inc eax
        jmp @b
        @@:
        pop eax
        ret
    zstrclrz endp


    zstrlenz proc src:dword
        push esi
        push ecx
        mov esi, src
        xor eax, eax
        @@:
        mov cl, [esi]
        cmp cl, 0
        jz @f
        inc eax
        inc esi
        jmp @b
        @@:
        pop ecx
        pop esi
        ret
    zstrlenz endp


    align 16
    namebytetable label byte
        db 48 dup (0)
        db 10 dup (1)
        db 7  dup (0)
        db 26 dup (1)
        db 4 dup  (0)
        db         1
        db         0
        db 26 dup (1)
        db 5 dup  (0)

Attachment 'basic editor14.zip' removed but is included in the archive In this post
« Last Edit: November 17, 2022, 12:45:41 PM by zedd151 »
Regards, zedd.
:tongue: