; ==================== source-file :_searchch_rev.asm ===================
;
; This source-code is part of the:
; "32-bit Assembly Language and 'C' Extensions for Visual Prolog"
;
;          ( Copyright: See the comment at the end of this file. )
;
COMMENT ~
;  Purpose: Backward search for a character, inside a string.
;  Features: 1) The backward search from any given inititial position (4-arg version).
;                      2) A "character-table number" can be invoked to make the search
;                          slightly "fuzzy" (5-argument version), e.g. to ignore case.
;
; GLOBAL PREDICATES
;   STRING searchch_rev(STRING input,CHAR ch,UNSIGNED posx) -(i,i,o) language c
;   STRING searchch_rev(STRING input,CHAR ch,UNSIGNED inpos,UNSIGNED pox)
;                  -(i,i,i,o) language c
;   STRING searchch_rev(STRING input,CHAR ch,UNSIGNED inpos,UNSIGNED casectb,UNSIGNED pox)
;                  -(i,i,i,i,o) language c

    IDEAL
P586
    MODEL    FLAT

    DATASEG
    extrn    ctb:near

    CODESEG
ALIGN 4

    PUBLIC  _searchch_rev_0
    PUBLIC  _searchch_rev_1
    PUBLIC  _searchch_rev_2

    extrn   _RUN_Fail:near  ; Visual Prolog's "fail"



PROC    _searchch_rev_0    NEAR
ARG string:dword, charsep:dword, posfndx:dword
    push    ebp    ;
    mov    ebp,esp ;
    push    esi    ;
    push    edi    ;
    push    ebx    ;
; ------------------------------
    mov    edi,[string]    ; EDI Pointer to string (ARG1)
    cld            ;
    xor    ecx,ecx ;
    mov    eax,ecx ;
    not    ecx     ;
    repne    scasb ;
    not    ecx     ; now ECX = length of string
    dec    edi     ; one less for end of string
    dec    edi     ;
    dec    ecx     ;
    mov    ebx,edi ; store it also in EBX
    mov    al,[charsep]    ; separator char in AL
    std            ; backwards
    repne    scasb ; search backwards for char
    jnz    @@xxx   ; if not found, exit program with failure
    inc    ecx     ;
    mov    ebx,ecx ;
    cld            ;
    jmp    @@zzz   ;
; ========================
@@xxx:    cld            ;
    call    _RUN_Fail    ;Prolog FAILURE
; ------------------------
@@zzz:    cld            ;
    mov    eax,edi       ;
    inc    eax           ;
    inc    eax           ; return  string AFTER the char
    mov    edx,[posfndx] ; ARG3 (output) position found
    mov    [edx],ebx     ;
    pop    ebx           ;
    pop    edi           ;
    pop    esi           ;
    pop    ebp           ;
    ret
ENDP    _searchch_rev_0

PROC    _searchch_rev_1    NEAR
ARG string:dword, charsep:dword, inputpo:dword, posfndx:dword
    push    ebp       ;
    mov    ebp,esp    ;
    push    esi       ;
    push    edi       ;
    push    ebx       ;
; ------------------------------
    mov    edi,[string]    ; EDI Pointer to string (ARG1)
    cld               ;
    xor    ecx,ecx    ;
    mov    eax,ecx    ;
    not    ecx        ;
    repne    scasb    ;
    not    ecx        ; now ECX = length of string
    dec    edi        ; one less for end of string
    dec    edi        ;
    dec    ecx        ;
    mov ebx,edi       ; store it also in EBX
    mov al,[charsep]    ; separator char in AL
    std               ; backwards
    mov edx,[inputpo]   ;
    dec    edx        ;
    mov edi,[string]    ; else (again) EDI Pointer to string (ARG1)
    cmp    edx,ecx    ;
    jbe    @@ok2      ; if input pos =< length, a valid position!
    mov    edx,ecx    ;
    jmp    @@ok3      ;
@@ok2:
    mov    ecx,edx    ;

@@ok3:
    add    edi,edx    ; go to position

    inc    ecx        ;
    repne    scasb    ; search backwards for char
    jnz    @@xx2      ; if not found, exit program with failure
    inc    ecx        ;
    mov    ebx,ecx    ;
    cld               ;
    jmp    @@zz2      ;
; =====================
@@xx2:    cld         ;
    call    _RUN_Fail ;Prolog FAILURE
; ---------------------
@@zz2:    cld         ;
    mov    eax,edi    ;
    inc    eax        ;
    inc    eax        ; return  string AFTER the char
    mov    edx,[posfndx]    ; ARG4 (output) position found
    mov    [edx],ebx  ;
    pop    ebx        ;
    pop    edi        ;
    pop    esi        ;
    pop    ebp        ;
    ret
ENDP    _searchch_rev_1

PROC    _searchch_rev_2    NEAR
ARG    binary:dword,char1:byte,inipos:dword,ctbnum:dword,outpos:dword
    push    ebp
    mov    ebp,esp
    push    esi
    push    ebx
    cld               ;
    mov edi,[binary]  ; EDI pointer to binary (ARG 1)
    mov    ecx,[dword ptr edi-4]
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    mov edx,[ctbnum]  ; ctb_number in EBX    (ARG 4)
    or    edx,edx     ; is it zero?
    jnz    @@ok1      ; if not so, case-sensitive search
; ---------------------
    mov al,[char1]    ; AL to char wanted (ARG2)
    mov edx,[inipos]  ; EDX to initial position (ARG3)
    dec    edx        ;   
    add    edi,edx    ; go to initial pos.
    mov    ebx,ecx    ;
    sub    ecx,edx    ;
    repne    scasb    ; search for 1st char of substring
    jz    @@p1        ; if found, exit with position found
; ---------------------
    mov    eax,edi    ;
    call    _RUN_Fail ; if not found, call Visual Prolog's "failure"
    jmp    @@xx4      ;
; =====================
@@p1:
    sub    ebx,ecx    ;

    dec    ebx        ; minus 1, since binaries begin at Zero
    mov    eax,edi    ; return RIGHT side of the string after the char
    jmp    @@xx4      ; exit
; ================= CASE-INSENSITIVE SEARCH begins here ================
@@ok1:    dec    edx        ;
    shl    edx,1            ;
    shl    edx,1            ;
    mov    ebx,[dword ptr ctb+edx]    ; ebx is now the Nth char_table
; -------------------------------------
    mov     esi,edi        ; ESI pointer to binary (ARG 1)
    push    esi        ; save the string-pointer in the stack
; =====================
     mov al, [char1]  ; AL to char wanted        (ARG 2)
     mov edx,[inipos] ; EDX to initial position    (ARG 3)
     add    esi,edx   ; add position to start
     xlat     [ebx]   ; translate original char
     mov    ah,al     ; store translated char in AH
     std              ; backward search
@@CQ1:     lodsb      ; load a char
     xlat    [ebx]    ; translate it
     cmp    al,ah     ; compare it to the (translated) character
     jz    @@fd       ; if it is the same, found! exit with success
     loop     @@CQ1   ; if not found, continue this loop till ECX=0
; ---------------------
@@xx:    pop    edx   ; Failure; balance the stack
@@x2:
    xor    ebx,ebx    ; just in case...

    cld               ; forwards
    call    _RUN_Fail ; call Visual Prolog "failure"
    jmp    @@xx3      ;
; =====================
@@fd:    pop    edx   ; else, FOUND!, recover string-start in EDX
    mov    ebx,esi    ; copy current str_pointer to EBX
    inc    ebx        ;
    inc    ebx        ;
    sub    ebx,edx    ; subtract to get position found
@@xx3:
    mov    eax,esi    ; return Right-hand-side in EAX

    inc    eax        ;
@@xx4:    cld         ;
    mov edx,[outpos]  ; found position = output ARG 4
    mov [edx],ebx     ;
    pop    ebx
    pop    esi
    pop    ebp
    ret
ENDP    _searchch_rev_2

    end

; ===================== VISUAL PROLOG test-program: ========================

ifdef test_searchstr_rev
GOAL
  repeat, S = "1234567890this LEFTisRIGHT a substring which is LEFT1okRIGHT and this end XX",
  str_len(S,Le), write("string = \"",S,"\", len=",Le,"\ngive a substring:"), readln(Sub1),
  write("\nsubstring = [",Sub1,"]\n"), % search_len = ", len), nl, readchar(_),
  S1a = searchstr_rev(S,Sub1,Px), write("Px=",Px,", S1a=\"",S1a,"\"\n"),
  write("give an initial position: "), readint(INIpos),
  S1b = searchstr_rev(S,Sub1,INIpos,Pz), write("Pz=",Pz,", S1b=\"",S1b,"\"\n"),
  readchar(CHx), CHx = '\27', !.
enddef

/*************************** COPYRIGHT ISSUES: *******************************


                      This source-code is part of the:
         "32-bit Assembly Language and 'C' Extensions for Visual Prolog"

This source-code is free for use in any application, provided this copyright
message is preserved intact, and the author is mentioned explicitly.

Author: George A. Stathis
Author's e-mail: omadeon@yahoo.com, gstathis@enm.gr
Author's personal URL: http://www.omadeon.com
Company URL:  http://www.enb.gr
*******************************************************************************/