sequential_read equ 0 debugging equ 0 pagesize 86 HT equ 09h LF equ 0ah CR equ 0dh LINENEW equ CR+LF*256 ;the way a newline is stored in memory. include bufseg.a86 ;buffer definitions data dseg byte public ;the following externs are in 'buffers' extrn textseg:word insert_ds rw 1 if sequential_read read_pointer rw 1 endif ;data ends code cseg byte public ;all the routines in this segment are entered with ds=data, es=data ;assume ### cs:code, ds:data, es:data ;the following externs are in 'marks' extrn init_marks:near,get_mark:near extrn adjust_marks_del:near,adjust_marks_ins:near ;the following externs are in 'redisp' extrn prevline:near,nextline:near,compute_one:near public count_lines count_lines: push ds ! mov ds,textseg call count_lines? pop ds ! ret public del_to_mark del_to_mark: push ds ! mov ds,textseg call del_to_mark? pop ds ! ret public read_mark read_mark: mov ds,textseg call read_mark? ret public goto_mark goto_mark: push ds ! mov ds,textseg call goto_mark? pop ds ! ret public insert_string insert_string: push ds ! mov ax,es ;use data for insert_ds. mov ds,textseg call insert_string? pop ds ! ret public set_column set_column: push ds ! mov ds,textseg call set_column? pop ds ! ret public set_line set_line: push ds ! mov ds,textseg call set_line? pop ds ! ret public compute_cursor compute_cursor: push ds ! mov ds,textseg call compute_cursor? ;exit with dx=column. pop ds ! ret public store_buffer_modified store_buffer_modified: push ds ! mov ds,textseg ;assume ### ds:bufseg mov buffer_modified,al pop ds ;assume ### ds:data ret public read_linecount read_linecount: mov bx,offset linecount jmps read_variable public read_linesbefore read_linesbefore: mov bx,offset linesbefore jmps read_variable public read_buffer_modified read_buffer_modified: mov bx,offset buffer_modified read_variable: push ds ! mov ds,textseg ;assume ### ds:bufseg mov ax,[bx] ! pop ds ;assume ### ds:data ret public file_size file_size: mov ds,textseg ;exit with ax=size of the ;assume ### ds:bufseg ; current buffer in bytes. mov ax,topbot sub ax,toptop add ax,botbot sub ax,bottop push es ! pop ds ;assume ### ds:data ret public percent_full percent_full: push ds ! mov ds,textseg ;return the percent full ;assume ### ds:bufseg ; amount in ax. mov ax,100 ! mov cx,memsize ;destroy ax,cx,dx. jcxz percent_full_1 mov ax,botbot ! sub ax,bottop ;compute the size add ax,topbot ! sub ax,toptop ; of the buffer mov dx,0 ! div cx or dx,dx ! jz $+3 inc ax ! pop ds percent_full_1: ;assume ### ds:data ret if sequential_read public reset_to_top reset_to_top: push es ! mov es,textseg ;assume ### es:bufseg mov ax,toptop mov read_pointer,ax pop es ;assume ### es:data ret public read_next read_next: mov bx,read_pointer push es ! mov es,textseg ;assume ### es:bufseg cmp bx,topbot ;time to switch to bottom? jb read_next_1 ;no. mov bx,bottop read_next_1: cmp bx,botbot ;end of file? jb read_next_2 ;no. stc ! jmps read_next_3 read_next_2: mov al,[bx] ! inc bx mov read_pointer,bx clc read_next_3: pop es ;assume ### es:data ret public goto_read goto_read: ;remember not to go to the LF part of a newline! ret ;for now, do nothing. endif if debugging extrn chrout:near,get_next_buffer:near public dump_bufseg dump_bufseg: mov ds,textseg ;assume ### ds:bufseg push linesbefore ! push linecount push botbot ! push bottop push topbot ! push toptop mov ax,es ! mov ds,ax ;assume ### ds:data mov ax,textseg ! call hexout pop ax ! call hexout ;toptop pop ax ! call hexout ;topbot pop ax ! call hexout ;bottop pop ax ! call hexout ;botbot pop ax ! call hexout ;linecount pop ax ! call hexout ;linesbefore call get_next_buffer ; call hexout ; ret ; fall through hexout: push ax ! mov ax,' ' ;print a leading space. call chrout pop ax ! push ax mov al,ah ! call byteout pop ax byteout: push ax ! shrb al,4 call nibout ! pop ax nibout: and al,0fh ! add al,90h daa ! adc al,40h daa ! mov ah,0 jmp chrout endif ;code ends code cseg ;ment byte public ;all the code in this segment is entered with ds=bufseg, es=data ;assume ### cs:code, ds:bufseg, es:data ;the following externs are in 'redisp' extrn paint_window:near,trash_line:near extrn window_insert:near,window_delete:near extrn up_lines:near,down_lines:near public init_vars? init_vars?: mov bx,bufseg_size+2 mov word ptr 0fffeh[bx],LINENEW mov toptop,bx ! mov topbot,bx mov bottop,bx ! mov botbot,bx mov word ptr [bx],LINENEW mov linecount,0 mov linesbefore,0 mov buffer_modified,0 ret public insert_string? insert_string?: ;enter with si,cx describing the string to insert, ax=segment of string. ;exit with cy if there isn't enough room to insert the entire string. mov es:insert_ds,ax jcxz insert_string_1 mov ax,bottop ! sub ax,topbot ;compute the free space. cmp ax,cx ;is there enough room for this string? jb insert_string_4 ;no - give error. mov buffer_modified,1 insert_string_2:push ds ! mov ds,es:insert_ds ;get an entire word, even mov ax,ds:[si] ;though we might use only the low byte. pop ds cmp ax,LINENEW ;newline? jne insert_string_3 ;no. cmp cx,2 ;must be at least two chars left. jb insert_string_3 ;no - can't be newline. push cx ! push si call inscrlf pop si ! pop cx inc si ! inc si ! dec cx loop insert_string_2 jmps insert_string_1 insert_string_3:push cx ! push si call insone pop si ! pop cx inc si ! loop insert_string_2 insert_string_1:clc ! ret insert_string_4:stc ! ret insone: cmp al,CR ! jne insone_1 mov bx,bottop cmp byte ptr [bx],LF jne inschar inc bottop jmps insone_2 insone_1: cmp al,LF ! jne inschar mov bx,topbot cmp byte ptr 0ffffh[bx],CR jne inschar dec topbot insone_2: mov ax,1 call adjust_marks_del call inscrlf ret inschar: ;insert the character in al at the point. ;unless there is no room. mov bx,topbot ! cmp bx,bottop jae inschar_1 push ax ! mov ax,1 call adjust_marks_ins pop ax mov di,topbot ! mov [di],al inc di mov topbot,di call trash_line inschar_1: ret inscrlf: mov bx,topbot ! inc bx cmp bx,bottop jae inscrlf_3 mov ax,2 call adjust_marks_ins mov di,topbot mov word ptr [di],LINENEW inc di ! inc di ! mov topbot,di inc linesbefore ! inc linecount call window_insert ;say that we inserted a line here. inscrlf_3: ret del_to_mark?: call get_mark jcxz del_to_mark_4_j_1 mov buffer_modified,1 jc del_to_mark_2 ;go if point>mark push bottop call move_point_backward ;swap point and mark (sort of). pop si ;pushed as bottop. del_to_mark_2: mov di,toptop ! cmp di,topbot ;are we at the beginning of the file? jne del_to_mark_1 ;no cmp si,botbot ;deleting to the end of the file? jne del_to_mark_1 ;no mov ax,si ! sub ax,bottop;compute the number of chars deleted. mov bottop,si ;no characters left. call adjust_marks_del mov linecount,0 ;no lines left. call paint_window ;trash the window. del_to_mark_4_j_1:jmps del_to_mark_4 ;now exit. del_to_mark_1: mov bp,si ;save the char that we delete to. mov ax,si ;compute the number of chars. sub ax,bottop call adjust_marks_del ;fix up the marks first. mov si,bottop ;get the -> first char to delete. del_to_mark_3: cmp word ptr [si],LINENEW ;a newline? jne del1_1 ;no - just skip this char. inc si ;extra inc to skip past the CR. dec linecount ;one less line. call window_delete ;fix up the window. del1_1: inc si ! cmp bp,si jne del_to_mark_3 mov bottop,si call trash_line ;now check for a newly created newline. mov bx,topbot ! cmp byte ptr 0ffffh[bx],CR jne del_to_mark_4 mov bx,bottop ! cmp byte ptr [bx],LF jne del_to_mark_4 ;get rid of the LF and CR seperately so that any mark that points to either ; one will point to the newline. inc bottop ;get rid of the LF mov ax,1 call adjust_marks_del dec topbot ;get rid of the CR mov ax,1 call adjust_marks_del call inscrlf ;now insert a newline. del_to_mark_4: ret public goto_mark? goto_mark?: call get_mark jcxz goto_mark_1 jnc goto_mark_2 call move_point_forward jmps goto_mark_1 goto_mark_2: call move_point_backward goto_mark_1: ret public read_mark? read_mark?: call get_mark jnc read_mark_1 mov si,bottop read_mark_1: ret move_point_backward: mov si,topbot ! mov di,bottop push es ! push ds ! pop es std ! dec si ! dec di push cx ! rep movsb ! pop cx inc si ! inc di ! cld ! pop es mov topbot,si ! mov bottop,di call count_lines? sub linesbefore,bx call up_lines ret move_point_forward: mov si,bottop ! mov di,topbot push di ! push cx ! push es push ds ! pop es rep movsb ! pop es mov bottop,si ! mov topbot,di pop cx ! pop di call count_lines? add linesbefore,bx call down_lines ret count_lines?: ;count the number of newlines contained in the text described by ds:di,cx. push es ! push ds ! pop es mov bx,0 count_lines_1: mov al,CR ! repnz scasb jcxz count_lines_2 cmp byte ptr [di],LF jne count_lines_1 inc bx ! jmps count_lines_1 count_lines_2: pop es ! ret public set_line? set_line?: ;given a line number in ax, move to that line. dec ax ;linesbefore is zero based. or ax,ax ;if negative, use zero. jns set_line_0 xor ax,ax set_line_0: sub ax,linesbefore je set_line_1 ;go if we're already on that line. jb set_line_2 ;go if we're after that line. mov cx,ax mov si,bottop set_line_4: call nextline loopne set_line_4 mov cx,si ;compute the number of characters. sub cx,bottop call move_point_forward jmps set_line_1 set_line_2: neg ax ! mov cx,ax ;ax is the number of lines to move. mov si,topbot cmp word ptr 0fffeh[si],LINENEW;are we at the beginning of a line? je set_line_3 ;yes. call prevline ;no, go to the beginning of the line. set_line_3: call prevline loopne set_line_3 mov cx,topbot ;compute the number of characters. sub cx,si call move_point_backward set_line_1: ret set_column?: ;given a column number in ax, move to that column. mov bx,ax ;save the column number in bx. dec bx ;columns are zero based. mov si,topbot jmps set_column?_2 set_column?_1: dec si set_column?_2: cmp word ptr 0fffeh[si],LINENEW jne set_column?_1 ;now move over to the point, counting the size of characters on the way. mov dx,0 mov cx,topbot sub cx,si jcxz set_column?_3 set_column?_4: cmp dx,bx ;are we at or past the desired column? jae set_column?_6 ;yes - move the point backward. lodsb call compute_one loop set_column?_4 set_column?_3: ;the desired column is somewhere after the point. mov si,bottop set_column?_7: cmp dx,bx ;are we at or past the desired column? jae set_column?_5 ;yes - go to the column. cmp word ptr [si],LINENEW;are we at the end of the line? je set_column?_5 ;yes - this is as close as we can get. lodsb ;compute the next character. call compute_one jmps set_column?_7 set_column?_5: mov cx,si ! sub cx,bottop call move_point_forward ret set_column?_6: call move_point_backward ret public compute_cursor? compute_cursor?: ;return the column in dx. mov si,topbot ;find the beginning of this line. jmps compute_cursor?_2 compute_cursor?_1: dec si compute_cursor?_2: cmp word ptr 0fffeh[si],LINENEW jne compute_cursor?_1 ;now move over to the point, counting the size of characters on the way. mov dx,0 ! mov cx,topbot sub cx,si ! jcxz compute_cursor?_3 compute_cursor?_4: lodsb ! call compute_one loop compute_cursor?_4 compute_cursor?_3: ret ;code ends end