
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.

find_first:
	mov	[search_flags],eax
	call	release_search_data
	or	esi,esi
	jz	nothing_to_search_for
	mov	edi,esi
	xor	al,al
	xor	ecx,ecx
	sub	ecx,edi
	repne	scasb
	lea	ebx,[edi-1]
	sub	ebx,esi
	jz	nothing_to_search_for
	lea	ecx,[(256+ebx)*4+ebx]
	push	ebx
	call	get_memory
	or	eax,eax
	jz	not_enough_memory
	mov	[search_data],eax
	mov	[search_handle],ebx
	pop	ebx
	mov	edi,eax
	lea	ecx,[256+ebx]
	mov	eax,ebx
	rep	stosd
	mov	ecx,ebx
	mov	ebx,[search_data]
	mov	edx,ecx
	test	[search_flags],FEFIND_BACKWARD
	jnz	text_for_backward_search
	test	[search_flags],FEFIND_CASESENSITIVE
	jnz	copy_search_text
	push	ebx
	mov	ebx,upper_case_table
    convert_search_text:
	lodsb
	xlatb
	stosb
	loop	convert_search_text
	pop	ebx
	jmp	make_character_shifts_table
    copy_search_text:
	rep	movsb
	jmp	make_character_shifts_table
    text_for_backward_search:
	add	edi,ecx
	mov	edx,ecx
	push	ebx
	mov	ebx,upper_case_table
    reverse_search_text:
	lodsb
	test	[search_flags],FEFIND_CASESENSITIVE
	jnz	reverse_store_character
	xlatb
    reverse_store_character:
	dec	edi
	mov	[edi],al
	dec	ecx
	jnz	reverse_search_text
	pop	ebx
	add	edi,edx
	xor	ecx,ecx
    make_character_shifts_table:
	cmp	edx,ecx
	je	character_shifts_table_ok
	dec	edi
	jecxz	character_shift_ok
	mov	al,[edi]
	cmp	[ebx+eax*4],edx
	jne	character_shift_ok
	mov	[ebx+eax*4],ecx
    character_shift_ok:
	inc	ecx
	jmp	make_character_shifts_table
    character_shifts_table_ok:
	lea	edi,[ebx+(256+ecx)*4]
	push	edi
	lea	edi,[edi+ecx-2]
	movzx	eax,byte [edi+1]
	mov	edx,[ebx+eax*4]
	mov	[ebx+256*4],edx
	cmp	ecx,1
	je	suffix_match_shifts_table_done
	mov	ecx,2
	mov	esi,edi
	sub	esi,edx
    make_suffix_match_shifts_table:
	cmp	esi,[esp]
	jb	store_suffix_match_shift
	mov	al,[esi]
	cmp	al,[edi]
	je	store_suffix_match_shift
    find_suffix_match:
	dec	esi
	inc	edx
	cmp	esi,[esp]
	jb	match_part_of_suffix
	push	ecx esi edi
	repe	cmpsb
	pop	edi esi ecx
	jne	find_suffix_match
	jmp	store_suffix_match_shift
    match_part_of_suffix:
	mov	eax,[esp]
	push	ecx esi edi
	xchg	eax,esi
	sub	eax,esi
	add	ecx,eax
	repe	cmpsb
	pop	edi esi ecx
	jne	suffix_match_shifts_table_done
    store_suffix_match_shift:
	mov	[ebx+256*4+(ecx-1)*4],edx
	dec	esi
	dec	edi
	inc	ecx
	cmp	ecx,[ebx]
	jbe	make_suffix_match_shifts_table
    suffix_match_shifts_table_done:
	pop	eax

find_next:
	mov	edi,[search_data]
	or	edi,edi
	jz	nothing_to_search_for
	push	[caret_line]
	push	[caret_line_number]
	push	[caret_position]
	push	[selection_position]
	test	[search_flags],FEFIND_BACKWARD
	jnz	search_backward
	test	[search_flags],FEFIND_INWHOLETEXT
	jz	search_for_text
	mov	eax,[first_line]
	mov	[caret_line],eax
	xor	eax,eax
	mov	[caret_position],eax
	inc	eax
	mov	[caret_line_number],eax
    search_for_text:
	mov	ecx,[edi]
	dec	ecx
	add	ecx,[caret_position]
	mov	esi,[caret_line]
	cmp	ecx,[peak_line_length]
	jae	text_not_in_this_line
	mov	[caret_position],ecx
	call	get_caret_segment
	mov	edi,[search_data]
	mov	eax,[edi]
	lea	ebx,[edi+(256+eax)*4]
	mov	ah,[ebx+eax-1]
	mov	ebx,upper_case_table
    search_in_line:
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	text_not_in_this_line
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	test	[search_flags],FEFIND_CASESENSITIVE
	jnz	compare_last_character
	xlatb
    compare_last_character:
	cmp	al,ah
	je	partial_match
    mismatch_shift:
	movzx	ecx,al
	mov	ecx,[edi+ecx*4]
    shift_search_position:
	add	edx,ecx
	add	ecx,[caret_position]
	cmp	ecx,[peak_line_length]
	jae	text_not_in_this_line
	mov	[caret_position],ecx
    check_search_position:
	cmp	edx,SEGMENT_DATA_LENGTH
	jb	search_in_line
	mov	ecx,[esi]
	btr	ecx,0
	jnc	search_in_line
	sub	edx,SEGMENT_DATA_LENGTH
	mov	esi,ecx
	jmp	check_search_position
    partial_match:
	mov	ecx,[edi]
	dec	ecx
	jz	text_found
	push	edi
	lea	edi,[edi+(256+ecx+1)*4]
	lea	edi,[edi+ecx]
    compare_text:
	sub	edx,1
	jc	compare_in_previous_segment
	dec	edi
	mov	al,20h
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	compare_character
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	test	[search_flags],FEFIND_CASESENSITIVE
	jnz	compare_character
	xlatb
    compare_character:
	cmp	al,[edi]
	loope	compare_text
	pop	edi
	je	text_found
	neg	ecx
	add	ecx,[edi]
	dec	ecx
	add	edx,ecx
	mov	ecx,[edi+(256+ecx-1)*4]
	jmp	shift_search_position
    compare_in_previous_segment:
	mov	esi,[esi+4]
	and	esi,not 1
	mov	edx,SEGMENT_DATA_LENGTH
	jmp	compare_text
    text_not_in_this_line:
	mov	esi,[esi]
	or	esi,esi
	jz	text_not_found
	btr	esi,0
	jc	text_not_in_this_line
    search_in_next_line:
	mov	[caret_line],esi
	inc	[caret_line_number]
	mov	[caret_position],0
	mov	edi,[search_data]
	jmp	search_for_text
    text_found:
	mov	eax,[caret_position]
	inc	eax
	mov	[selection_position],eax
	sub	eax,[edi]
	mov	[caret_position],eax
	jz	left_text_edge_ok
	test	[search_flags],FEFIND_WHOLEWORDS
	jz	left_text_edge_ok
	mov	edi,[search_data]
	mov	ecx,[edi]
	mov	al,[edi+(256+ecx)*4]
	call	recognize_character
	jc	left_text_edge_ok
	dec	[caret_position]
	call	get_caret_segment
	inc	[caret_position]
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	left_text_edge_ok
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	call	recognize_character
	jnc	found_not_acceptable
    left_text_edge_ok:
	mov	eax,[caret_position]
	xchg	eax,[selection_position]
	mov	[caret_position],eax
	mov	edi,[search_data]
	mov	ecx,[edi]
	lea	edi,[edi+(256+ecx)*4]
	mov	al,[edi+ecx-1]
	cmp	al,20h
	je	right_text_edge_blank
	test	[search_flags],FEFIND_WHOLEWORDS
	jz	right_text_edge_ok
	call	recognize_character
	jc	right_text_edge_ok
	call	get_caret_segment
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	right_text_edge_ok
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	call	recognize_character
	jc	right_text_edge_ok
	mov	eax,[selection_position]
	mov	[caret_position],eax
    found_not_acceptable:
	mov	edi,[search_data]
	mov	ecx,[edi]
	mov	eax,[edi+(256+ecx-1)*4]
	add	[caret_position],eax
	jmp	search_for_text
    right_text_edge_blank:
	call	get_caret_segment
    check_for_blank_end:
	mov	ecx,SEGMENT_DATA_LENGTH
	sub	ecx,edx
	jz	blank_end_next_segment
	push	edi
	mov	al,20h
	lea	edi,[esi+SEGMENT_HEADER_LENGTH+edx]
	repe	scasb
	pop	edi
	jne	right_text_edge_ok
    blank_end_next_segment:
	mov	esi,[esi]
	or	esi,esi
	jz	text_not_found
	btr	esi,0
	jnc	search_in_next_line
	xor	edx,edx
	jmp	check_for_blank_end
    right_text_edge_ok:
	mov	eax,[caret_line]
	mov	ecx,[caret_line_number]
	mov	[selection_line],eax
	mov	[selection_line_number],ecx
	and	[search_flags],not FEFIND_INWHOLETEXT
	add	esp,16
	clc
	retn
    text_not_found:
	pop	[selection_position]
	pop	[caret_position]
	pop	[caret_line_number]
	pop	[caret_line]
    nothing_to_search_for:
	stc
	retn
    search_backward:
	test	[search_flags],FEFIND_INWHOLETEXT
	jz	backward_search_for_text
	or	eax,-1
	call	find_line
	mov	[caret_line],esi
	mov	[caret_line_number],ecx
	call	move_to_line_end
    backward_search_for_text:
	mov	ecx,[caret_position]
	sub	ecx,1
	jc	backward_text_not_in_this_line
	mov	[caret_position],ecx
	mov	edi,[search_data]
	mov	eax,[edi]
	mov	al,[edi+(256+eax)*4]
	cmp	al,20h
	jne	backward_search_starting_position_ok
	mov	esi,[caret_line]
	mov	ecx,[esi+8]
	mov	edi,[search_data]
	mov	eax,[edi]
	sub	ecx,eax
	jc	backward_text_not_in_this_line
	cmp	ecx,[caret_position]
	jae	backward_search_starting_position_ok
	mov	[caret_position],ecx
    backward_search_starting_position_ok:
	call	get_caret_segment
	mov	edi,[search_data]
	mov	eax,[edi]
	lea	ebx,[edi+(256+eax)*4]
	mov	ah,[ebx+eax-1]
	mov	ebx,upper_case_table
	cmp	edx,SEGMENT_DATA_LENGTH
	jb	backward_search_in_line
	mov	ecx,edx
	sub	ecx,SEGMENT_DATA_LENGTH-1
	sub	edx,ecx
	sub	[caret_position],ecx
    backward_search_in_line:
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	test	[search_flags],FEFIND_CASESENSITIVE
	jnz	compare_first_character
	xlatb
    compare_first_character:
	cmp	al,ah
	je	backward_partial_match
    backward_mismatch_shift:
	movzx	ecx,al
	mov	ecx,[edi+ecx*4]
    shift_backward_search_position:
	sub	edx,ecx
	sub	[caret_position],ecx
	jc	backward_text_not_in_this_line
    check_backward_search_position:
	cmp	edx,0
	jge	backward_search_in_line
	mov	esi,[esi+4]
	and	esi,not 1
	add	edx,SEGMENT_DATA_LENGTH
	jmp	check_backward_search_position
    backward_partial_match:
	mov	ecx,[edi]
	dec	ecx
	jz	backward_text_found
	push	edi
	lea	edi,[edi+(256+ecx+1)*4]
	lea	edi,[edi+ecx]
    backward_compare_text:
	inc	edx
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	compare_in_next_segment
	dec	edi
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	test	[search_flags],FEFIND_CASESENSITIVE
	jnz	backward_compare_character
	xlatb
    backward_compare_character:
	cmp	al,[edi]
	loope	backward_compare_text
	pop	edi
	je	backward_text_found
	neg	ecx
	add	ecx,[edi]
	dec	ecx
	sub	edx,ecx
	mov	ecx,[edi+(256+ecx)*4]
	jmp	shift_backward_search_position
    compare_in_next_segment:
	sub	edx,SEGMENT_DATA_LENGTH
	mov	esi,[esi]
	btr	esi,0
	jnc	compare_blank_space
	dec	edx
	jmp	backward_compare_text
    compare_blank_space:
	pop	edi
	cmp	ecx,[edi]
	jbe	backward_text_found
    backward_text_not_in_this_line:
	mov	esi,[caret_line]
	mov	esi,[esi+4]
	or	esi,esi
	jz	text_not_found
	mov	[caret_line],esi
	dec	[caret_line_number]
	mov	ecx,[peak_line_length]
	mov	[caret_position],ecx
	jmp	backward_search_for_text
    backward_text_found:
	test	[search_flags],FEFIND_WHOLEWORDS
	jz	backward_left_text_edge_ok
	cmp	[caret_position],0
	je	backward_left_text_edge_ok
	mov	edi,[search_data]
	mov	ecx,[edi]
	lea	edi,[edi+(256+ecx)*4]
	mov	al,[edi+ecx-1]
	call	recognize_character
	jc	backward_left_text_edge_ok
	dec	[caret_position]
	call	get_caret_segment
	inc	[caret_position]
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	backward_left_text_edge_ok
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	call	recognize_character
	jnc	backward_found_not_acceptable
    backward_left_text_edge_ok:
	mov	eax,[caret_position]
	mov	[selection_position],eax
	mov	edi,[search_data]
	mov	ecx,[edi]
	add	eax,ecx
	mov	[caret_position],eax
	test	[search_flags],FEFIND_WHOLEWORDS
	jz	backward_right_text_edge_ok
	mov	al,[edi+(256+ecx)*4]
	call	recognize_character
	jc	backward_right_text_edge_ok
	call	get_caret_segment
	cmp	edx,SEGMENT_DATA_LENGTH
	jae	backward_right_text_edge_ok
	mov	al,[esi+SEGMENT_HEADER_LENGTH+edx]
	call	recognize_character
	jc	backward_right_text_edge_ok
	mov	eax,[selection_position]
	mov	[caret_position],eax
    backward_found_not_acceptable:
	mov	edi,[search_data]
	mov	ecx,[edi]
	mov	eax,[edi+(256+ecx-1)*4]
	sub	[caret_position],eax
	jbe	backward_text_not_in_this_line
	jmp	backward_search_for_text
    backward_right_text_edge_ok:
	mov	eax,[caret_position]
	xchg	eax,[selection_position]
	mov	[caret_position],eax
	mov	eax,[caret_line]
	mov	ecx,[caret_line_number]
	mov	[selection_line],eax
	mov	[selection_line_number],ecx
	and	[search_flags],not FEFIND_INWHOLETEXT
	add	esp,16
	clc
	retn

get_search_text_length:
	mov	ecx,[search_data]
	test	ecx,ecx
	jz	no_search_text
	mov	ecx,[ecx]
	clc
	retn
get_search_text:
	mov	esi,[search_data]
	test	esi,esi
	jz	no_search_text
	mov	ecx,[esi]
	lea	esi,[esi+(256+ecx)*4]
	test	[search_flags],FEFIND_BACKWARD
	jnz	copy_inverted_text
	rep	movsb
	xor	al,al
	stosb
	clc
	retn
    copy_inverted_text:
	mov	al,[esi+ecx-1]
	stosb
	loop	copy_inverted_text
	xor	al,al
	stosb
	clc
	retn
    no_search_text:
	stc
	retn

release_search_data:
	mov	edi,[search_data]
	test	edi,edi
	jz	search_data_released
	mov	ebx,[search_handle]
	call	release_memory
	mov	[search_data],0
    search_data_released:
	retn
