; ==================== source-file :_nd_search.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: non-deterministic search for a character, sub-string or sub-binary,
;   inside a string or a binary.

;   Produces all the positions where a certain character or  sub-string or sub-
;   binary is found inside a string or a binary at each non-deterministic call;
;   it then fails, after all positions have been found.
;
; NOTE: Can be called with "findall/3", to find ALL the positions where a
;    char, sub-string, or sub-binary is located, inside a string or a binary.


    IDEAL
P586
    MODEL    FLAT

    DATASEG
ALIGN 4
    extrn    ctb:dword

    CODESEG
ALIGN 4
; ======= first two variants deal with strings only (most common):
    public _nd_search_0    ;(STRING,CHAR,posx)
    public _nd_search_1    ;(STRING,STRING,posx)

; ======= next three variants deal with binaries:
    public _nd_search_2    ;(BINARY,CHAR,posx)
    public _nd_search_3    ;(BINARY,STRING,posx)
    public _nd_search_4    ;(BINARY,BINARY,posx)

; ======= next two variants accept an "initial position"(arg 3):
    public _nd_search_5    ;(STRING,CHAR,inpos,posx)
    public _nd_search_6    ;(STRING,STRING,inpos,posx)

; ======= next three variants deal with binaries, accepting "initial position"(arg 3):
    public _nd_search_7    ;(BINARY,CHAR,inpos,posx)
    public _nd_search_8    ;(BINARY,STRING,inpos,posx)
    public _nd_search_9    ;(BINARY,BINARY,inpos,posx)

; ======= next two variants take a "case char-table"(arg 4), and init_pos(arg 3):
    public _nd_search_10    ;(STRING,CHAR,inpos,case,posx)
    public _nd_search_11    ;(STRING,STRING,inpos,case,posx)

; ======= next 3 variants take "case" and "initial position" but deal with binaries:
    public _nd_search_12    ;(BINARY,CHAR,inpos,case,posx)
    public _nd_search_13    ;(BINARY,STRING,inpos,case,posx)
    public _nd_search_14    ;(BINARY,BINARY,inpos,case,posx)
   
Macro pushx3   
    push    esi
    push    edi
    push    ebx
    endm

Macro popx3   
    pop    ebx
    pop    edi
    pop    esi
    ret
    endm

    extrn    _MEM_AllocGStack:near
    extrn    _MEM_AdjustGStackAlloc:near
    extrn    _RUN_Fail:near
    extrn    _RUN_JmpReturn:near
    extrn    _RUN_StackBTrack:near
    extrn    _RUN_JmpReturn1:near
    extrn    _MEM_MakeBinaryGStack:near


PROC _nd_search_0 near        ; (STRING,CHAR,UNSIGNED) -(i,i,o)
ENTER    12,0            ;
ARG    strg1:dword,char1:byte,outpx:dword
    pushx3
    mov esi,[strg1]  ; string input.............. ARG-1(input)
    mov [ebp-8], esi ;
    mov ah,[char1]   ; char ..................... ARG-2(input)
    mov [ebp-4], eax ;
; -------------------
@@LP0:
    mov eax,[ebp-4]  ;

@@LP0a:   
    lodsb            ;

    cmp    al,ah     ;
    jz    @@ok1      ;
    or    al,al      ;
    jz    @@XZ1      ; if zero, fail at end of string
    jmp    @@LP0a    ; else repeat THIS loop
; =========================
@@ok1:
    mov    [ebp-8],esi    ; store it

    call _RUN_StackBTrack ; stack a 'backtrack point' in Visual Prolog
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax         ; is the result (of StackBTrack) zero?
    jne    @@LP0          ; if not, read more...
; -------------------------
    mov    eax,esi        ; return right_hand_side string (after the char)
    mov    ecx,eax        ;
    mov ebx,[strg1]       ; string input.............. ARG-1(input)
    sub    ecx,ebx        ;
    mov edx,[outpx]       ; give Position of Char .... ARG-3(output)
    mov    [edx],ecx      ;
    call _RUN_JmpReturn1  ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    jmp    @@LP0          ; repeat big loop
; =========================
@@XZ1:    call _RUN_Fail  ; FAIL
    popx3
LEAVE
ENDP _nd_search_0


PROC _nd_search_1 near    ;  (STRING,STRING,POSITION) -(i,i,o)
ENTER    16,0    ;
ARG    strg1:dword,substr:dword,outpx:dword
    pushx3
    mov edi,[substr]     ; substring................ ARG-2(input)
    cmp [byte ptr edi],0 ; special case of substr=""?
    jnz    @@Laa         ; if not so, normal processing
; ------------------------
    jmp    @@XZ1         ; else, fail
    mov    edi,[strg1]   ;
    xor    eax,eax       ;
    mov    ecx,eax       ;
    not    ecx           ;
    repne    scasb       ;
    not    ecx           ;
    mov     edx,[outpx]  ; give Position of substring.... ARG-3(output)
    mov    [edx],ecx     ;
    jmp    @@XZ2         ;
; ========================
@@Laa:    mov esi,[strg1]; string input..............ARG-1(input)
    mov    [ebp-8], esi  ;
    mov    [ebp-4], edi  ;
@@LP0:   
    mov    edi,[ebp-4]   ;

    mov ah,[byte ptr edi]; first char of substring in AH
@@LP0a:    lodsb         ;
    cmp    al,ah         ;
    jz    @@ok1          ;
    or    al,al          ;
    jz    @@XZ1          ; if zero, fail at end of string
    jmp    @@LP0a        ; else repeat THIS loop
; ========================
@@ok1:    push    esi    ;
@@ok2:     inc    edi    ;
     lodsb               ;
     cmp    al,[byte ptr edi]
     jz    @@ok2         ;
     mov    al,[byte ptr edi]
     or    al,al         ;
     jz    @@ok3         ;
    pop    esi           ;
    jmp    @@LP0         ;
@@ok3:
     mov    ebx,esi      ;

    pop    esi           ;
    mov    [ebp-8],esi   ; store esi
    mov    [ebp-12],ebx  ; store right_hand_string after the substring
    call _RUN_StackBTrack; stack a 'backtrack point' in Visual Prolog
    mov    esi,[ebp-8]   ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0         ; if not, read more...
; ------------------------
@@ZZ:
    mov    eax,[ebp-12]  ; return right_hand_side string (after the char)

    mov    ecx,esi       ;
    mov ebx,[strg1]      ; string input.................. ARG-1(input)
    sub    ecx,ebx       ;
    mov edx,[outpx]      ; give Position of substring.... ARG-3(output)
    mov    [edx],ecx     ;
    call _RUN_JmpReturn1 ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]   ;
    jmp    @@LP0         ; repeat big loop
; ========================
@@XZ1:    call _RUN_Fail ; FAIL
@@XZ2:    popx3
LEAVE
ENDP _nd_search_1


PROC _nd_search_2 near   ; (BINARY,CHAR,UNSIGNED) -(i,i,o)
ENTER    16,0            ;
ARG    binary:dword,char1:byte,outpx:dword
    pushx3
    mov esi,[binary]    ; binary input.............. ARG-1(input)
    mov ecx,[dword ptr esi-4]    ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    mov [ebp-8], esi    ;
    mov ah,[char1]        ; char ..................... ARG-2(input)
    mov [ebp-4], eax    ;
    mov [ebp-12],ecx    ;
@@LP0:    mov    eax,[ebp-4]    ;
    mov    ecx,[ebp-12]    ;
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
    or    al,al        ;
    jz    @@XZ1        ; if zero, fail at end of string
    jmp    @@LP0a        ; else repeat THIS loop
; ===============================
@@ok1:    mov    [ebp-8],esi    ; store it
    mov [ebp-12],ecx    ;
    call _RUN_StackBTrack    ; stack a 'backtrack point' in Visual Prolog
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0        ; if not, read more...
; -------------------------------
    mov    eax,esi        ; return right_hand_side string (after the char)
    mov    ecx,eax        ;
    mov ebx,[binary]        ; string input.............. ARG-1(input)
    sub    ecx,ebx        ;
    dec    ecx        ; binaries start at zero   
    mov edx,[outpx]        ; give Position of Char .... ARG-3(output)
    mov    [edx],ecx    ;
    call _RUN_JmpReturn1    ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    jmp    @@LP0        ; repeat big loop
; ===============================
@@XZ1:    call _RUN_Fail        ; FAIL
    popx3
LEAVE
ENDP _nd_search_2


PROC _nd_search_3 near        ; (BINARY,STRING,POSITION) -(i,i,o)
ENTER    20,0    ;
ARG    strg1:dword,substr:dword,outpx:dword
    pushx3
    mov edi,[substr]    ; substring................ ARG-2(input)
    mov esi,[strg1]        ; BINARY input..............ARG-1(input)
    mov    [ebp-8], esi    ;
    mov    [ebp-4], edi    ;
    mov    ecx,[dword ptr esi-4]    ;
    dec    ecx
    dec    ecx
    dec    ecx
    mov    [ebp-16],ecx    ; length of binary in local variable

@@LP0:    mov    edi,[ebp-4]    ;
    mov ah,[byte ptr edi]    ; first char of substring in AH
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
;or    al,al        ;
;jz    @@XZ1        ; if zero, fail at end of string
    dec    ecx        ;
    or    ecx,ecx        ;
    jz    @@XZ1        ;
    jmp    @@LP0a        ; else repeat THIS loop
; ===============================
@@ok1:   
    dec    ecx        ;
    or    ecx,ecx        ;
    jz    @@XZ1        ;
    mov    [ebp-16],ecx    ;
    push    esi        ;
@@ok2:     inc    edi        ;
     lodsb            ;
     cmp    al,[byte ptr edi]
     jz    @@ok2        ;
     mov    al,[byte ptr edi]
     or    al,al        ;
     jz    @@ok3        ;
    pop    esi        ;
    jmp    @@LP0        ;
; ===============================
@@ok3:     mov    ebx,esi        ;
    pop    esi        ;
    mov    [ebp-8],esi    ; store esi
    mov    [ebp-12],ebx    ; store right_hand_string after the substring
    mov    [ebp-16],ecx    ; remaining length recovered
    call _RUN_StackBTrack    ; stack a 'backtrack point' in Visual Prolog
    mov    ecx,[ebp-16]    ; remaining length recovered
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0        ; if not, read more...
; -------------------------------
@@ZZ:    mov    eax,[ebp-12]    ; return right_hand_side string (after the char)
    mov    ecx,esi        ;
    mov ebx,[strg1]        ; string input.................. ARG-1(input)
    sub    ecx,ebx        ;
    mov edx,[outpx]        ; give Position of substring.... ARG-3(output)
    dec    ecx        ; binaries start at zero   
    mov    [edx],ecx    ;
    call _RUN_JmpReturn1    ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    mov    ecx,[ebp-16]    ; remaining length recovered
    jmp    @@LP0        ; repeat big loop
; ===============================
@@XZ1:    mov    [ebp-16],ecx    ;
    call _RUN_Fail        ; FAIL
@@XZ2:    popx3
LEAVE
ENDP _nd_search_3



PROC _nd_search_4 near    ; (BINARY,BINARY,POSITION) -(i,i,o)
ENTER    24,0
ARG    binary:dword,subbin:dword,outpx:dword
    pushx3
    mov edi,[subbin]    ; sub-binary............... ARG-2(input)
    mov ecx,[dword ptr edi-4] ; "true length" of sub-binary in ECX
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ; length of sub_binary_array in ECX
    dec    ecx        ; minus 1
    mov    [ebp-20],ecx    ; store length of sub-binary-1 in local variable
    mov    edx,ecx        ; copy it also to EDX
    mov esi,[binary]    ; binary input..............ARG-1(input)
    mov ecx,[dword ptr esi-4] ; "true length" of binary in ECX
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ; length of binary_array in ECX
    dec    ecx        ;
    mov    [ebp-8], esi    ;
    sub    ecx,edx        ; subtrack sub_bin_length from binary length!
    dec    ecx
    mov    [ebp-16],ecx    ; store length of binary in local variable
    mov    [ebp-4], edi    ;
@@LP0:   
;;or    ecx,ecx        ;
;;jz    @@XZ1        ;
    mov    edi,[ebp-4]    ;
    or    ecx,ecx        ;
    jz    @@XZ1        ;
     mov ah,[byte ptr edi]    ; first char of subbinary in AH
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
    loop    @@LP0a        ;
    jmp    @@XZ1        ; if exhausted, fail
; ===============================
@@ok1:    dec    ecx        ;
    or    ecx,ecx        ;
    jz    @@XZ1        ;
    push    esi        ;
     push    ecx        ;
      mov    ecx,[ebp-20]    ; length of subbinary recovered from local var.
      jmp    @@ok2        ;
@@ok2a:      dec    ecx        ;
      jz    @@ok3        ;
@@ok2:      inc    edi        ;
      lodsb            ;
      cmp al,[byte ptr edi]    ;
      jz    @@ok2a        ;
     pop    ecx        ;
    pop    esi        ;
    jmp    @@LP0        ;
; ===============================
@@ok3:      mov    ebx,esi        ;
     pop    ecx        ;
    pop    esi        ;
    or    ecx,ecx        ;
    jz    @@XZ1        ;
    mov    [ebp-8],esi    ; store esi
    mov    [ebp-12],ebx    ; store right_hand_string after the substring
    mov    [ebp-16],ecx    ; store length in local variable
;or    ecx,ecx        ;
;jz    @@XZ1        ;
    call _RUN_StackBTrack    ; stack a 'backtrack point' in Visual Prolog
    mov    ecx,[ebp-16]    ; store length in local variable
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0        ; if not, read more...
; -------------------------------
    mov    eax,[ebp-12]    ; return right_hand_side string (after the sub-bin)
    mov    ecx,esi        ;
    mov ebx,[binary]    ; binary input.................. ARG-1(input)
    sub    ecx,ebx        ;
    dec    ecx        ; binaries start at zero   
    mov edx,[outpx]        ; give Position of substring.... ARG-3(output)
    mov    [edx],ecx    ;
    call _RUN_JmpReturn1    ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    mov    ecx,[ebp-16]    ; recover length from local variable
    jmp    @@LP0        ; repeat big loop
; ===============================
@@XZ1:    call _RUN_Fail        ; FAIL
    popx3
LEAVE
ENDP _nd_search_4


PROC _nd_search_5 near        ; (STRING,CHAR,inpos,posx) -(i,i,i,o)
ENTER    12,0            ;
ARG    strg1:dword,char1:byte,inpos:dword,outpx:dword
    pushx3
    mov esi,[strg1]        ; string input.............. ARG-1(input)
    mov    eax,[inpos]    ; initial position.......... ARG-2(input)
    dec    eax        ; minus one, because Prolog strings start at 1
    add    esi,eax        ; add the position to the string pointer
    mov [ebp-8], esi    ;
    mov ah,[char1]        ; char ..................... ARG-3(input)
    mov [ebp-4], eax    ;
; -------------------------------
@@LP0:    mov    eax,[ebp-4]    ;
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
    or    al,al        ;
    jz    @@XZ1        ; if zero, fail at end of string
    jmp    @@LP0a        ; else repeat THIS loop
; ===============================
@@ok1:    mov    [ebp-8],esi    ; store it
    call _RUN_StackBTrack    ; stack a 'backtrack point' in Visual Prolog
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0        ; if not, read more...
; -------------------------------
    mov    eax,esi        ; return right_hand_side string (after the char)
    mov    ecx,eax        ;
    mov ebx,[strg1]        ; string input.............. ARG-1(input)
    sub    ecx,ebx        ;
    mov edx,[outpx]        ; give Position of Char .... ARG-3(output)
    mov    [edx],ecx    ;
    call _RUN_JmpReturn1    ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    jmp    @@LP0        ; repeat big loop
; ===============================
@@XZ1:    call _RUN_Fail        ; FAIL
    popx3
LEAVE
ENDP _nd_search_5


PROC _nd_search_6 near    ;  (STRING,STRING,INIPOS,POSITION) -(i,i,i,o)
ENTER    16,0    ;
ARG    strg1:dword,substr:dword,inpos:dword,outpx:dword
    pushx3
    mov esi,[strg1]        ; string input..............ARG-1 (input)
    mov    [ebp-8], esi    ;
    mov edi,[substr]    ; substring................ ARG-2 (input)
    mov    eax,[inpos]    ; initial position......... ARG-3 (input)
    dec    eax        ; minus 1, since Prolog strings start with 1
    add    esi,eax        ; add initial position to the string
    mov    [ebp-4], edi    ;
@@LP0:    mov    edi,[ebp-4]    ;
    mov ah,[byte ptr edi]    ; first char of substring in AH
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
    or    al,al        ;
    jz    @@XZ1        ; if zero, fail at end of string
    jmp    @@LP0a        ; else repeat THIS loop
; ===============================
@@ok1:    push    esi        ;
@@ok2:     inc    edi        ;
     lodsb            ;
     cmp al,[byte ptr edi]    ;
     jz    @@ok2        ;
     mov al,[byte ptr edi]    ;
     or    al,al        ;
     jz    @@ok3        ;
    pop    esi        ;
    jmp    @@LP0        ;
@@ok3:     mov    ebx,esi        ;
    pop    esi        ;
    mov    [ebp-8],esi    ; store esi
    mov    [ebp-12],ebx    ; store right_hand_string after the substring
    call _RUN_StackBTrack    ; stack a 'backtrack point' in Visual Prolog
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0        ; if not, read more...
; -------------------------------
    mov    eax,[ebp-12]    ; return right_hand_side string (after the char)
    mov    ecx,esi        ;
    mov ebx,[strg1]        ; string input.................. ARG-1(input)
    sub    ecx,ebx        ;
    mov edx,[outpx]        ; give Position of substring.... ARG-3(output)
    mov    [edx],ecx    ;
    call _RUN_JmpReturn1    ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    jmp    @@LP0        ; repeat big loop
; ===============================
@@XZ1:    call _RUN_Fail        ; FAIL
    popx3
LEAVE
ENDP _nd_search_6


PROC _nd_search_7 near        ; (BINARY,CHAR,inpos,posx) -(i,i,i,o)
ENTER    16,0            ;
ARG    binary:dword,char1:byte,inpos:dword,outpx:dword
    pushx3
    mov esi,[binary]    ; binary input.............. ARG-1(input)
    mov ecx,[dword ptr esi-4]    ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    mov    eax,[inpos]    ; initial position.......... ARG-2(input)
    add    esi,eax        ; add initial position to binary pointer
    sub    ecx,eax        ; subtract init_pos from binary length
    mov [ebp-8], esi    ;
    mov ah,[char1]        ; char ..................... ARG-3(input)
    mov [ebp-4], eax    ;
    mov [ebp-12],ecx    ;
@@LP0:    mov    eax,[ebp-4]    ;
    mov    ecx,[ebp-12]    ;
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
    or    al,al        ;
    jz    @@XZ1        ; if zero, fail at end of string
    jmp    @@LP0a        ; else repeat THIS loop
; ===============================
@@ok1:    mov    [ebp-8],esi    ; store it
    mov [ebp-12],ecx    ;
    call _RUN_StackBTrack    ; stack a 'backtrack point' in Visual Prolog
    mov    esi,[ebp-8]    ; recover ESI
    or    eax,eax        ; is the result (of StackBTrack) zero?
    jne    @@LP0        ; if not, read more...
; -------------------------------
    mov    eax,esi        ; return right_hand_side string (after the char)
    mov    ecx,eax        ;
    mov ebx,[strg1]        ; string input.............. ARG-1(input)
    sub    ecx,ebx        ;
    dec    ecx        ; binaries start at zero   
    mov edx,[outpx]        ; give Position of Char .... ARG-3(output)
    mov    [edx],ecx    ;
    call _RUN_JmpReturn1    ; call Visual Prolog function "_RUN_JmpReturn1"
    mov    esi,[ebp-8]    ;
    jmp    @@LP0        ; repeat big loop
; ===============================
@@XZ1:    call _RUN_Fail        ; FAIL
    popx3
LEAVE
ENDP _nd_search_7


PROC _nd_search_8 near    ;  (BINARY,STRING,INIPOS,POSITION) -(i,i,i,o)
ENTER    20,0    ;
ARG    binary:dword,substr:dword,inpos:dword,outpx:dword
    pushx3
    mov esi,[binary]    ; binary input..............ARG-1 (input)
    mov    ecx,[dword ptr esi-4]    ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ;
    dec    ecx        ; ecx is now length of binary
    mov    [ebp-8], esi    ;
    mov edi,[substr]    ; substring................ ARG-2 (input)
    mov    eax,[inpos]    ; initial position......... ARG-3 (input)
    add    esi,eax        ; add initial position to the string
    sub    ecx,eax        ; subtract it from the length
    mov    [ebp-4], edi    ;
    mov    [ebp-16],ecx    ; store the length as a local variable
@@LP0:    mov    edi,[ebp-4]    ;
    mov    ecx,[ebp-16]    ; restore the length from local variable
    mov ah,[byte ptr edi]    ; first char of substring in AH
@@LP0a:    lodsb            ;
    cmp    al,ah        ;
    jz    @@ok1        ;
    dec    ecx        ;
    jz    @@XZ1        ; if at the end, fail
    jmp    @@LP0a        ; else repeat THIS loop
; ===============================
@@ok1:    push    esi        ;