asm_dip/toolchain/fasm2/source/ide/edit.inc
2024-11-25 00:04:53 -05:00

1028 lines
19 KiB
PHP

; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
set_text:
push esi
call reset_editor_memory
pop esi
mov ebx,[first_line]
or esi,esi
jz new_text_ok
set_text_line:
call set_line
jc new_text_ok
call allocate_segment
mov [ebx],eax
jc not_enough_memory
mov ebx,eax
mov eax,[caret_line]
mov [ebx+4],eax
mov [caret_line],ebx
inc [lines_count]
inc [caret_line_number]
jmp set_text_line
new_text_ok:
xor eax,eax
mov dword [ebx],eax
inc eax
mov [caret_line_number],eax
mov eax,[first_line]
mov [caret_line],eax
mov [caret_position],0
retn
put_character:
call get_caret_segment
inc [caret_position]
put_here:
cmp edx,SEGMENT_DATA_LENGTH
jae put_after_line_end
call store_segment_for_undo
test [editor_mode],FEMODE_OVERWRITE
jnz overwrite
mov ah,[esi+SEGMENT_HEADER_LENGTH+edx]
shl eax,8
mov al,ah
insert_in_segment:
lea ebx,[esi+SEGMENT_HEADER_LENGTH+edx]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
shift_data_right:
xchg al,[ebx]
inc ebx
loop shift_data_right
test byte [esi],1
jnz shift_next_segment_right
cmp al,20h
je put_ok
add_segment:
push eax
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov edi,eax
or eax,1
xchg eax,[esi]
stosd
mov eax,esi
or eax,1
stosd
add edi,SEGMENT_HEADER_LENGTH - 8
pop eax
stosb
mov ecx,SEGMENT_DATA_LENGTH - 1
mov al,20h
rep stosb
jmp put_ok
shift_next_segment_right:
mov esi,[esi]
dec esi
call store_segment_for_undo
xor edx,edx
jmp insert_in_segment
put_after_line_end:
push eax
call attach_empty_segments
pop eax
mov [esi+SEGMENT_HEADER_LENGTH+edx],al
mov ah,20h
shl eax,8
put_ok:
test [editor_style],FES_AUTOBRACKETS
jz insert_done
shr eax,8
xchg ah,al
call recognize_character
jnc insert_done
cmp ah,'('
je round
cmp ah,'['
je square
cmp ah,'{'
je brace
insert_done:
retn
round:
mov al,')'
jmp auto_bracket
square:
mov al,']'
jmp auto_bracket
brace:
mov al,'}'
auto_bracket:
mov edx,[caret_position]
mov esi,[caret_line]
call find_segment
jmp put_here
overwrite:
mov [esi+SEGMENT_HEADER_LENGTH+edx],al
retn
attach_empty_segments:
call store_segment_for_undo
attach_segment:
push edx
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
pop edx
mov ebx,esi
mov esi,eax
mov edi,eax
or eax,1
xchg eax,[ebx]
stosd
mov eax,ebx
or eax,1
stosd
add edi,SEGMENT_HEADER_LENGTH - 8
mov ecx,SEGMENT_DATA_LENGTH shr 2
mov eax,20202020h
rep stosd
sub edx,SEGMENT_DATA_LENGTH
cmp edx,SEGMENT_DATA_LENGTH
jae attach_segment
retn
recognize_character:
cmp al,20h
jb neutral_character
cmp al,30h
jb separator_character
cmp al,3Ah
jb neutral_character
cmp al,40h
jb separator_character
cmp al,5Bh
jb neutral_character
cmp al,5Fh
jb separator_character
cmp al,7Bh
jb neutral_character
cmp al,7Fh
jb separator_character
neutral_character:
clc
retn
separator_character:
stc
retn
delete_character:
call get_caret_segment
delete_here:
cmp edx,SEGMENT_DATA_LENGTH
jae delete_done
call store_segment_for_undo
test [editor_mode],FEMODE_OVERWRITE
jnz blank
lea ebx,[esi+SEGMENT_LENGTH]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov al,20h
mov edi,[esi]
test edi,1
jz shift_data_left
mov al,[edi-1+SEGMENT_HEADER_LENGTH]
shift_data_left:
dec ebx
xchg al,[ebx]
loop shift_data_left
lea esi,[edi-1]
xor edx,edx
test edi,1
jnz delete_here
delete_done:
retn
blank:
mov byte [esi+SEGMENT_HEADER_LENGTH+edx],20h
retn
tabulate:
test [editor_style],FES_SMARTTABS
jz standard_tab
mov esi,[caret_line]
mov esi,[esi+4]
or esi,esi
jz standard_tab
mov edx,[caret_position]
call find_segment
cmp edx,SEGMENT_DATA_LENGTH
jae standard_tab
push 0
find_space:
lea edi,[esi+SEGMENT_HEADER_LENGTH+edx]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov ebx,ecx
mov al,20h
repne scasb
jne no_space_in_this_segment
sub ebx,ecx
dec ebx
add edx,ebx
add [esp],ebx
call get_indent
pop ecx
or ebx,ebx
jz standard_tab
add ecx,ebx
jmp insert_tab_spaces
no_space_in_this_segment:
pop ecx
mov esi,[esi]
btr esi,0
jnc standard_tab
add ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
xor edx,edx
push ecx
jmp find_space
standard_tab:
mov ecx,[caret_position]
and ecx,not 111b
sub ecx,[caret_position]
add ecx,8
insert_tab_spaces:
xor esi,esi
push ecx
call insert_into_line
pop ecx
add [caret_position],ecx
retn
carriage_return:
xor ebx,ebx
test [editor_style],FES_AUTOINDENT
jz auto_indent_ok
test [editor_mode],FEMODE_OVERWRITE
jnz auto_indent_ok
call get_caret_segment
call get_indent
add [caret_position],ebx
mov esi,[caret_line]
xor edx,edx
call get_indent
auto_indent_ok:
call break_line
retn
get_indent:
xor ebx,ebx
find_indent_origin:
cmp edx,SEGMENT_DATA_LENGTH
jb find_indent
mov esi,[esi]
btr esi,0
jnc no_indent
sub edx,SEGMENT_DATA_LENGTH
jmp find_indent_origin
find_indent:
lea edi,[esi+SEGMENT_HEADER_LENGTH+edx]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
add ebx,ecx
mov al,20h
repe scasb
je segment_indent
sub ebx,ecx
dec ebx
retn
segment_indent:
xor edx,edx
mov esi,[esi]
btr esi,0
jc find_indent
no_indent:
xor ebx,ebx
retn
break_line:
test [editor_mode],FEMODE_OVERWRITE
jnz go_to_next_line
push ebx
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov edi,eax
mov eax,[caret_line]
mov [edi+4],eax
mov ebx,[esp]
push edi
add edi,SEGMENT_HEADER_LENGTH
mov ecx,SEGMENT_DATA_LENGTH shr 2
mov eax,20202020h
rep stosd
call get_caret_segment
call store_segment_for_undo
mov edi,[esp]
cmp edx,SEGMENT_DATA_LENGTH
jae empty_new_line
push esi edx
new_line_segment:
cmp ebx,SEGMENT_DATA_LENGTH
jb new_line_segments_ok
push edi ebx
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov esi,eax
lea edi,[esi+SEGMENT_HEADER_LENGTH]
mov ecx,SEGMENT_DATA_LENGTH shr 2
mov eax,20202020h
rep stosd
pop ebx edi
sub ebx,SEGMENT_DATA_LENGTH
mov eax,esi
or eax,1
mov [edi],eax
or edi,1
mov [esi+4],edi
mov edi,esi
jmp new_line_segment
new_line_segments_ok:
pop edx esi
split_data:
cmp ebx,edx
jbe indent_data
push esi edi
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,ebx
lea esi,[esi+SEGMENT_HEADER_LENGTH+edx]
lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx]
add edx,ecx
mov eax,ecx
rep movsb
mov edi,esi
sub edi,eax
mov ecx,eax
mov al,20h
rep stosb
push edx
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
pop edx edi esi
mov ebx,eax
or eax,1
mov [edi],eax
or edi,1
mov [ebx+4],edi
mov edi,ebx
xor ebx,ebx
jmp split_data
indent_data:
push edi
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov eax,ecx
lea esi,[esi+SEGMENT_HEADER_LENGTH+edx]
lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx]
rep movsb
add ebx,eax
mov edi,esi
sub edi,eax
mov ecx,eax
mov al,20h
rep stosb
pop edi
mov eax,[esp]
xchg eax,[esi-SEGMENT_LENGTH]
btr eax,0
jnc finish_new_line
shift_splitted_data:
mov esi,eax
or eax,1
mov [edi],eax
call store_segment_for_undo
mov eax,edi
or eax,1
mov [esi+4],eax
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,ebx
lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx]
add esi,SEGMENT_HEADER_LENGTH
mov eax,esi
rep movsb
mov edi,eax
mov ecx,ebx
rep movsb
sub edi,ebx
sub edi,SEGMENT_HEADER_LENGTH
mov eax,[edi]
btr eax,0
jc shift_splitted_data
finish_new_line:
mov esi,edi
call store_segment_for_undo
mov [edi],eax
pop esi
or eax,eax
jz new_line_pointers_ok
xchg esi,eax
call store_segment_for_undo
xchg esi,eax
mov [eax+4],esi
new_line_pointers_ok:
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,ebx
lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx]
mov al,20h
rep stosb
xchg [caret_line],esi
call check_line_length
mov esi,[caret_line]
mov dword [esi+8],0
call check_line_length
inc [caret_line_number]
inc [lines_count]
pop [caret_position]
retn
empty_new_line:
pop edi
mov eax,[esi]
mov [esi],edi
mov [edi],eax
or eax,eax
jz empty_line_pointers_ok
mov [eax+4],edi
empty_line_pointers_ok:
mov dword [edi+8],0
mov [caret_line],edi
inc [caret_line_number]
inc [lines_count]
pop [caret_position]
retn
go_to_next_line:
mov [caret_position],ebx
mov esi,[caret_line]
skip_line_segments:
mov eax,[esi]
btr eax,0
jnc line_segments_skipped
mov esi,eax
jmp skip_line_segments
line_segments_skipped:
or eax,eax
jz no_next_line
mov [caret_line],eax
next_line_ok:
inc [caret_line_number]
retn
no_next_line:
call store_segment_for_undo
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov [esi],eax
mov edi,eax
xchg eax,[caret_line]
mov [edi+4],eax
xor eax,eax
stosd
add edi,4
stosd
add edi,SEGMENT_HEADER_LENGTH - 12
mov ecx,SEGMENT_DATA_LENGTH shr 2
mov eax,20202020h
rep stosd
inc [lines_count]
jmp next_line_ok
cut_line_break:
test [editor_mode],FEMODE_OVERWRITE
jnz do_nothing
call get_caret_segment
cmp edx,SEGMENT_DATA_LENGTH
jbe segment_for_deleting_ok
call store_segment_for_undo
add_empty_segment:
push edx esi
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
pop ebx edx
mov esi,eax
mov edi,eax
or eax,1
xchg eax,[ebx]
stosd
mov eax,ebx
or eax,1
stosd
add edi,SEGMENT_HEADER_LENGTH - 8
mov ecx,SEGMENT_DATA_LENGTH shr 2
mov eax,20202020h
rep stosd
sub edx,SEGMENT_DATA_LENGTH
cmp edx,SEGMENT_DATA_LENGTH
ja add_empty_segment
segment_for_deleting_ok:
call store_segment_for_undo
mov edi,esi
mov esi,[esi]
btr esi,0
jc append_segment
call cancel_line
append_segment:
or esi,esi
jz fill_rest_with_spaces
call store_segment_for_undo
or byte [edi],1
lea eax,[edi+1]
mov [esi+4],eax
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov eax,ecx
add esi,SEGMENT_HEADER_LENGTH
lea edi,[edi+SEGMENT_HEADER_LENGTH+edx]
rep movsb
mov edi,esi
sub edi,eax
mov ecx,edx
rep movsb
sub esi,SEGMENT_LENGTH
mov edi,esi
mov esi,[esi]
btr esi,0
jc append_segment
fill_rest_with_spaces:
lea edi,[edi+SEGMENT_HEADER_LENGTH+edx]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov al,20h
rep stosb
or esi,esi
jz delete_done
call store_segment_for_undo
mov eax,[caret_line]
mov [esi+4],eax
do_nothing:
retn
cancel_line:
dec [lines_count]
mov eax,[esi+8]
call unregister_length
cmp esi,[window_line]
jne window_line_ok
mov eax,[caret_line]
mov [window_line],eax
mov eax,[caret_line_number]
mov [window_line_number],eax
window_line_ok:
cmp esi,[first_line]
jne first_line_ok
mov eax,[caret_line]
mov [first_line],eax
first_line_ok:
retn
insert_into_line:
or ecx,ecx
jz void_insert
push ecx esi
call get_caret_segment
test [editor_mode],FEMODE_OVERWRITE
jnz overwrite_in_line
cmp edx,SEGMENT_DATA_LENGTH
jae attach_after_line_end
mov eax,[esp+4]
push edx
xor edx,edx
mov ecx,SEGMENT_DATA_LENGTH
div ecx
mov ebx,esi
push esi
or edx,edx
jnz find_last_segment_to_shift
call store_segment_for_undo
mov esi,[esi]
btr esi,0
jnc following_segments_shifted
call store_segment_for_undo
jmp following_segments_shifted
find_last_segment_to_shift:
test byte [ebx],1
jz shift_following_segments
mov ebx,[ebx]
dec ebx
jmp find_last_segment_to_shift
shift_following_segments:
push edx
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
pop edx
mov edi,eax
mov esi,[ebx]
mov [edi],esi
mov eax,ebx
or eax,1
mov [edi+4],eax
lea edi,[edi+SEGMENT_HEADER_LENGTH+edx]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov al,20h
rep stosb
sub edi,SEGMENT_LENGTH
carry_to_next_segment:
mov esi,ebx
call store_segment_for_undo
mov eax,edi
or eax,1
mov [esi],eax
add esi,SEGMENT_LENGTH
sub esi,edx
mov ecx,edx
add edi,SEGMENT_HEADER_LENGTH
rep movsb
cmp ebx,[esp]
je following_segments_shifted
mov edi,ebx
mov ebx,[edi+4]
btr ebx,0
push edi
add edi,SEGMENT_LENGTH-1
mov esi,edi
sub esi,edx
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
std
rep movsb
cld
pop edi
jmp carry_to_next_segment
following_segments_shifted:
pop esi edx
insert_more_segments:
mov edi,esi
mov ecx,[esp+4]
make_inserted_segment:
sub ecx,SEGMENT_DATA_LENGTH
jb fill_inserted_segments
push ecx edx
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
pop edx ecx
mov ebx,[edi]
btr ebx,0
jnc make_attached_segment
or eax,1
mov [edi],eax
mov [ebx+4],eax
and eax,not 1
or ebx,1
mov [eax],ebx
or edi,1
mov [eax+4],edi
mov edi,eax
jmp make_inserted_segment
make_attached_segment:
or eax,1
mov [edi],eax
and eax,not 1
mov [eax],ebx
or edi,1
mov [eax+4],edi
mov edi,eax
jmp make_inserted_segment
fill_inserted_segments:
mov eax,SEGMENT_DATA_LENGTH
add ecx,eax
sub eax,edx
sub eax,ecx
jbe all_shifts_done
mov ecx,eax
lea edi,[edi+SEGMENT_LENGTH-1]
push esi
lea esi,[esi+SEGMENT_HEADER_LENGTH+ecx-1]
add esi,edx
std
rep movsb
cld
pop esi
all_shifts_done:
mov edi,esi
pop esi ebx
fill_new_segment:
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
cmp ecx,ebx
jbe length_for_inserting_ok
mov ecx,ebx
length_for_inserting_ok:
sub ebx,ecx
push edi
lea edi,[edi+SEGMENT_HEADER_LENGTH+edx]
or esi,esi
jz insert_blank_string
rep movsb
jmp string_inserted
insert_blank_string:
mov al,20h
rep stosb
string_inserted:
pop edi
mov edi,[edi]
and edi,not 1
xor edx,edx
or ebx,ebx
jnz fill_new_segment
retn
attach_after_line_end:
call attach_empty_segments
mov ebx,esi
pop esi
or esi,esi
jnz attach_string
pop ecx
retn
attach_string:
mov ecx,[esp]
mov eax,SEGMENT_DATA_LENGTH
sub eax,edx
cmp eax,ecx
jae length_to_attach_ok
mov ecx,eax
length_to_attach_ok:
sub [esp],ecx
lea edi,[ebx+SEGMENT_HEADER_LENGTH+edx]
rep movsb
mov ecx,[esp]
jecxz attach_ok
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov edi,eax
or eax,1
xchg eax,[ebx]
mov [edi],eax
or ebx,1
mov [edi+4],ebx
mov ebx,edi
xor edx,edx
jmp attach_string
attach_ok:
pop eax
lea ecx,[ebx+SEGMENT_LENGTH]
sub ecx,edi
mov al,20h
rep stosb
void_insert:
retn
overwrite_in_line:
cmp edx,SEGMENT_DATA_LENGTH
jb position_for_overwrite_ok
call attach_empty_segments
position_for_overwrite_ok:
mov edi,esi
pop esi ebx
overwrite_segment:
xchg esi,edi
call store_segment_for_undo
xchg esi,edi
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
cmp ecx,ebx
jbe length_to_overwrite_ok
mov ecx,ebx
length_to_overwrite_ok:
sub ebx,ecx
push edi
lea edi,[edi+SEGMENT_HEADER_LENGTH+edx]
or esi,esi
jz overwrite_with_blank
rep movsb
jmp overwritten_ok
overwrite_with_blank:
mov al,20h
rep stosb
overwritten_ok:
pop edi
or ebx,ebx
jz overwrite_done
push esi
mov esi,[edi]
btr esi,0
jc overwrite_existing_segment
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov edx,eax
or edx,1
mov [edi],edx
mov [eax],esi
or edi,1
mov [eax+4],edi
mov edi,eax
pop esi
xor edx,edx
cmp ebx,SEGMENT_DATA_LENGTH
jae overwrite_segment
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,ebx
lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx]
mov al,20h
rep stosb
sub edi,SEGMENT_LENGTH
jmp overwrite_segment
overwrite_existing_segment:
call store_segment_for_undo
mov edi,esi
xor edx,edx
pop esi
jmp overwrite_segment
overwrite_done:
retn
delete_from_line:
or ecx,ecx
jz nothing_to_delete
test [editor_mode],FEMODE_OVERWRITE
jnz clear_in_line
push ecx
add [caret_position],ecx
call get_caret_segment
pop ecx
sub [caret_position],ecx
cmp edx,SEGMENT_DATA_LENGTH
jae clear_rest_of_line
push esi edx
call get_caret_segment
call store_segment_for_undo
mov edi,esi
mov ebx,edx
pop edx esi
shift_over_deleted:
mov ecx,SEGMENT_DATA_LENGTH
mov eax,ecx
sub ecx,ebx
sub eax,edx
cmp eax,ecx
jae size_to_shift_ok
mov ecx,eax
size_to_shift_ok:
push esi edi
lea esi,[esi+SEGMENT_HEADER_LENGTH+edx]
lea edi,[edi+SEGMENT_HEADER_LENGTH+ebx]
add edx,ecx
add ebx,ecx
rep movsb
pop edi
cmp ebx,SEGMENT_DATA_LENGTH
je next_destination_segment
pop esi
cmp edx,SEGMENT_DATA_LENGTH
jne shift_over_deleted
mov esi,[esi]
btr esi,0
jnc cut_line
xor edx,edx
jmp shift_over_deleted
next_destination_segment:
mov esi,[edi]
btr esi,0
call store_segment_for_undo
mov edi,esi
pop esi
xor ebx,ebx
jmp shift_over_deleted
cut_line:
mov esi,edi
mov edx,ebx
jmp clear_from_here
clear_in_line:
xor esi,esi
jmp insert_into_line
clear_rest_of_line:
call get_caret_segment
cmp edx,SEGMENT_DATA_LENGTH
jae no_line_tail_to_clear
call store_segment_for_undo
clear_from_here:
lea edi,[esi+SEGMENT_HEADER_LENGTH+edx]
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
mov al,20h
rep stosb
mov ebx,esi
mov esi,[ebx]
remove_following_segments:
btr esi,0
jnc rest_of_line_cleared
call store_freed_segment_for_undo
mov esi,[esi]
jmp remove_following_segments
rest_of_line_cleared:
mov [ebx],esi
nothing_to_delete:
retn
no_line_tail_to_clear:
mov esi,[esi]
retn
remove_line:
mov esi,[caret_line]
mov esi,[esi]
or esi,esi
jnz cut_extra_segments
mov edi,[caret_line]
add edi,SEGMENT_HEADER_LENGTH
mov ecx,SEGMENT_DATA_LENGTH
mov al,20h
repe scasb
je line_removed
cut_extra_segments:
btr esi,0
jnc replace_with_next_line
call store_freed_segment_for_undo
mov esi,[esi]
jmp cut_extra_segments
replace_with_next_line:
or esi,esi
jz clear_current_line
call store_segment_for_undo
mov ebx,esi
xchg esi,[caret_line]
mov eax,[esi+4]
mov [ebx+4],eax
call store_freed_segment_for_undo
call cancel_line
mov esi,[esi+4]
or esi,esi
jz line_removed
find_last_segment_of_previous_line:
mov eax,[esi]
btr eax,0
jnc link_to_new_next_line
mov esi,eax
jmp find_last_segment_of_previous_line
link_to_new_next_line:
call store_segment_for_undo
mov [esi],ebx
line_removed:
mov [caret_position],0
mov [selection_line],0
retn
clear_current_line:
mov esi,[caret_line]
call store_segment_for_undo
mov dword [esi],0
lea edi,[esi+SEGMENT_HEADER_LENGTH]
mov ecx,SEGMENT_DATA_LENGTH
mov al,20h
rep stosb
jmp line_removed
duplicate_line:
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov esi,[caret_line]
mov edi,eax
mov [edi+4],esi
mov eax,[esi+8]
mov [edi+8],eax
call register_length
push edi
duplicate_segment:
mov ebx,edi
add edi,SEGMENT_HEADER_LENGTH
add esi,SEGMENT_HEADER_LENGTH
mov ecx,SEGMENT_DATA_LENGTH
rep movsb
sub esi,SEGMENT_LENGTH
mov eax,[esi]
btr eax,0
jnc all_segments_duplicated
mov esi,eax
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov edi,eax
or eax,1
mov [ebx],eax
or ebx,1
mov [edi+4],ebx
jmp duplicate_segment
all_segments_duplicated:
inc [lines_count]
call store_segment_for_undo
mov [ebx],eax
pop ebx
mov [esi],ebx
mov esi,eax
or esi,esi
jz duplicate_done
call store_segment_for_undo
mov [esi+4],ebx
duplicate_done:
retn
finish_edit:
mov esi,[caret_line]
call check_line_length
retn