pagesize 86 include mintdefs.a86 cr equ 0dh lf equ 0ah linenew equ 0a0dh include bufseg.a86 ;buffer definitions data dseg byte public extrn syntax_table: word extrn textseg: word ;Marks are referred to by a single ASCII character. If the mark is a digit, ; it is a user-defined mark. mark_first_temp equ '0' ;first temp mark mark_last_temp equ '9' ;last temp mark mark_first_perm equ '@' ;first permanent mark. mark_last_perm equ 'Z' ;last permanent mark. mark_split equ '*' ;split mark ;If the mark is one of the following characters, it is a system-defined mark. mark_list rb 0 db '>' ;character to the right of the point dw mark_right db '<' ;character to the left of the point. dw mark_left db '[' ;first character in the file. dw mark_top db ']' ;last character in the file. dw mark_bot db '^' ;beginning of this line. dw mark_begin db '$' ;end of this line. dw mark_end db '-' ;blanks to the left. dw mark_lblanks db '+' ;blanks to the right. dw mark_rblanks db '}' ;word to the right of this one. dw mark_word_right db '{' ;word to the left of this one. dw mark_word_left db '.' ;point or anything else no in the list. dw mark_point mark_list_size equ ((offset $)-(offset mark_list))/3 ;data ends code cseg byte public ;*** assume cs:code, ds:data, es:data public set_mark set_mark: push ds ! mov ds,textseg call set_mark? pop ds ! ret public stack_marks stack_marks: push ds ! mov ds,textseg call stack_marks? pop ds ! ret ;code ends code cseg byte public ;*** assume cs:code, ds:bufseg, es:data public init_marks public set_mark_si public get_mark public adjust_marks_del public adjust_marks_ins init_marks: mov temp_mark_base,1 mov temp_mark_count,1 mov perm_mark_count,1 mov bx,offset marks_sp+2 mov byte ptr [bx],0 ;initial stack frame is empty. mov marks_sp,bx mov mark_offset,0 ;init the only mark. mov split_mark,0 ;set the mark to the beginning. ret user_mark: ;enter with al=mark. ;if user mark, exit with bx->proper marks array entry, nc. ;if sytem mark, exit with cy. cmp al,mark_first_perm ;permanent user mark? jb user_mark_3 cmp al,mark_last_perm ja user_mark_3 mov bl,al sub bl,mark_first_perm cmp bl,perm_mark_count jae user_mark_1 ;too bit, can't be user mark. jmps user_mark_2 user_mark_3: cmp al,mark_first_temp jb user_mark_1 cmp al,mark_last_temp ja user_mark_1 mov bl,al sub bl,mark_first_temp mov bh,temp_mark_count ;compute the number of temporary marks. sub bh,temp_mark_base cmp bl,bh jae user_mark_1 ;too big, can't be user mark. add bl,temp_mark_base user_mark_2: add bl,bl mov bh,0 lea bx,mark_offset[bx] ret ;cy was cleared by previous operation user_mark_1: cmp al,mark_split ;split is a settable mark. jne user_mark_4 mov bx,offset split_mark ret user_mark_4: stc ret stack_marks?: ;enter with ax>0=number of temporary marks to stack or ; ax<0=number of permanent marks to create (temporary marks are destroyed) or ; ax=0 to unstack. ;exit with cy if overflow/underflow. cmp ax,0 jg stack_marks_1 ;stack jl stack_marks_4 ;create perms. mov bx,marks_sp mov al,[bx] ;get the current frame size or al,al je stack_marks_2 ;nothing to unstack. sub temp_mark_count,al ;reduce count by this frame size dec bx mov al,[bx] ;get the previous frame size sub temp_mark_base,al mov marks_sp,bx clc ret stack_marks_4: neg ax cmp al,MAX_MARKS ;stack overflow? jae stack_marks_2 ; yes. mov temp_mark_base,al mov temp_mark_count,al mov perm_mark_count,al mov bx,offset marks_sp ;find the new tos. add bx,ax mov byte ptr [bx],0 ;initial stack frame is empty. mov marks_sp,bx mov ax,'.'*256+mark_first_perm mov cl,perm_mark_count mov ch,0 jmps stack_marks_3 stack_marks_1: mov ah,temp_mark_count ;get number of marks. add ah,al ;add desired number cmp ah,MAX_MARKS ;stack overflow? jae stack_marks_2 ; yes. mov bx,marks_sp inc bx ;bump stack pointer mov [bx],al ;save the frame size mov marks_sp,bx mov al,temp_mark_count mov temp_mark_base,al ;new base is old max. mov temp_mark_count,ah ;new max is old+count of new marks ;set all the new temp marks to the point. sub ah,al ;ah=temp_mark_count-temp_mark_base mov cl,ah mov ch,0 mov ax,'.'*256+mark_first_temp stack_marks_3: push ax push cx call set_mark? pop cx pop ax inc al loop stack_marks_3 clc ret stack_marks_2: stc ret set_mark_si: ;enter with al=number of dest mark, si->text. ;note that system marks cannot be set. call user_mark jc set_mark_si_1 ;not a user mark. cmp si,topbot ;is new mark above point? jb set_mark_si_2 ;no, make it relative to toptop sub si,bottop add si,topbot sub si,toptop jmps set_mark_si_3 set_mark_si_2: sub si,toptop set_mark_si_3: mov [bx],si set_mark_si_1: ret set_mark?: ;enter with al=dest mark, ah=source mark. push ax mov al,ah call get_mark_count pop ax call user_mark jc set_mark_1 mov [bx],cx ;store the mark. set_mark_1: ret ;*** assume es:nothing, ss:data get_mark_count: ;enter with al=number of mark to get. ;exit with cx=number of characters before the mark. call user_mark jc get_mark_count_1 ;anything larger (or negative) mov cx,[bx] ret get_mark_count_1: mov bx,offset mark_list-3 ;get the mark list. mov cx,mark_list_size get_mark_count_2: ;scan the list for the mark. add bx,3 ;preincrement cmp al,ss:[bx] ;is it this one? loopne get_mark_count_2 ;continue if not. jmp ss:word ptr 1[bx] ;go to the correct mark. mark_right: mov cx,botbot ;compute the number of characters after the sub cx,bottop ; point. je mark_bot ; return the mark at the end of the file. mov cx,topbot ;compute the number of characters before the sub cx,toptop ; point. inc cx ;because we want the character to the right. mov bx,bottop ;check for breaking up a NEWLINE cmp word ptr [bx],LINENEW jne mark_right_1 ;not NEWLINE. inc cx ;because we don't want to split a newline. mark_right_1: ret mark_left: mov cx,topbot sub cx,toptop jz mark_left_1 ;if no characters, mark is at beginning of file. dec cx ;because we want the character to the left. mov bx,topbot cmp word ptr 0fffeh[bx],LINENEW jne mark_left_1 dec cx ;because we don't want to split a newline. mark_left_1: ret mark_top: mov cx,0 ;zero characters before beginning of file. ret mark_bot: mov cx,topbot ;size of text before point + sub cx,toptop add cx,botbot ;size of text after point. sub cx,bottop ret mark_point: mov cx,topbot ;size of text before point. sub cx,toptop ret mark_begin: mov cx,topbot mov bx,cx sub cx,toptop mark_begin_1: cmp word ptr 0fffeh[bx],LINENEW ;at beginning? je mark_begin_2 ;yes. dec bx dec cx jmp mark_begin_1 mark_begin_2: ret mark_end: mov cx,topbot ;start at point sub cx,toptop mov bx,bottop mark_end_1: cmp word ptr [bx],LINENEW ;at end? je mark_end_2 ;yes. inc bx inc cx jmp mark_end_1 mark_end_2: ret mark_word_right: mov cx,topbot ;start at point sub cx,toptop mov bx,bottop mark_word_right_1: cmp bx,botbot ;end of buffer is end of word. je mark_word_right_2 mov al,[bx] ;is this character a blank? call get_syntax test al,1 je mark_word_right_2 ;yes - we're done. inc bx inc cx jmp mark_word_right_1 mark_word_right_2: ret mark_word_left: mov cx,topbot ;start at point mov bx,cx sub cx,toptop jcxz mark_word_left_1 ;if nothing to the left, leave. dec bx mark_word_left_2: mov al,[bx] ;is this character a blank? call get_syntax test al,1 je mark_word_left_1 ;yes - exit now. dec bx dec cx jne mark_word_left_2 mark_word_left_1: ret mark_lblanks: mov cx,topbot ;start at point mov bx,cx sub cx,toptop jcxz mark_lblanks_1 ;if nothing to left, leave. dec bx cmp word ptr 0ffffh[bx],LINENEW ;starting at newline? jne mark_lblanks_2 ;no. sub cx,2 ;yes - move back over it. sub bx,2 jcxz mark_lblanks_1 ;if nothing more to left, leave. mark_lblanks_2: mov al,[bx] ;is this char a blank? call get_syntax test al,3 ;non-blank or line break? jne mark_lblanks_1 ;yes - exit now. dec bx dec cx jne mark_lblanks_2 mark_lblanks_1: ret mark_rblanks: mov cx,topbot ;start at point sub cx,toptop mov bx,bottop cmp word ptr [bx],LINENEW ;starting at newline? jne mark_rblanks_1 ;no. cmp bx,botbot ;starting at end of buffer? je mark_rblanks_2 ;yes - end. add bx,2 ;start by skipping the newline. add cx,2 mark_rblanks_1: cmp bx,botbot ;end of buffer is end of word. je mark_rblanks_2 ;yes - end. mov al,[bx] call get_syntax test al,3 ;non-blank or line break? jne mark_rblanks_2 ;yes - exit now. inc bx inc cx jmp mark_rblanks_1 mark_rblanks_2: ret public split_at_point split_at_point: ;return cy if the split mark is at or after the point. mov cx,split_mark mov ax,topbot sub ax,toptop cmp split_mark,ax ;is the split mark at or after the point? jae split_at_point_1 ;yes - return cy. clc ret split_at_point_1: stc ret public get_split_mark get_split_mark: ;same as get_mark('*'), only faster. mov cx,split_mark jmps compute_mark get_mark: ;enter with al=number of mark to get. call get_mark_count compute_mark: ;enter with cx=the number of characters before the point. ;exit with cx=count of chars between the mark and the point, si->text at mark, ;cy=1 if mark is after the point. mov si,topbot sub si,toptop sub cx,si jb compute_mark_1 mov si,bottop ;make si->bottom add si,cx ;make si->text. stc ret compute_mark_1: mov si,topbot ;Compute pointer to text. add si,cx ; cx is difference between topbot and mark, neg cx ; which is negative. make it positive. clc ret ;*** assume es:data adjust_marks_ins: ;enter with ax=number of characters inserted ;exit with all marks adjusted accordingly. ;if a mark is at or after the point, move it up or down. ;if a mark is before the point, leave it alone. mov cl,temp_mark_count mov ch,0 inc cx mov bx,offset mark_offset-2 mov dx,topbot sub dx,toptop adjust_marks_ins_1: mov si,[bx] ;get a mark cmp si,dx ;is it before the point? jb adjust_marks_ins_2 ;yes. adjust_marks_ins_3: add si,ax ;no - adjust it and store it back. mov [bx],si adjust_marks_ins_2: add bx,2 ;go to the next mark. loop adjust_marks_ins_1 ret adjust_marks_del: ;enter with ax=number of characters deleted. ;exit with all marks adjusted accordingly. ;if a mark is after the point, move it up or down. ;if a mark is at or before the point, leave it alone. ;Adjusting for deletion is more complex than adjusting for insertion, ; because we have to adjust all the marks that fall in the range of ; the characters deleted. mov cl,temp_mark_count mov ch,0 inc cx mov bx,offset mark_offset-2 mov dx,topbot sub dx,toptop ;make dx -> before first mark to adjust mov di,dx add di,ax ;make di -> last mark to adjust. adjust_marks_del_1: mov si,[bx] ;get a mark cmp si,dx ;is it at or before the point? jbe adjust_marks_del_2 ;yes. cmp si,di ;does it mark a deleted character? ja adjust_marks_del_3 ;no - adjust it down. mov [bx],dx ;all deleted marks will mark the point. jmps adjust_marks_del_2 adjust_marks_del_3: sub si,ax ;no - adjust it and store it back. mov [bx],si adjust_marks_del_2: add bx,2 ;go to the next mark. loop adjust_marks_del_1 ret ;*** assume es:nothing public get_syntax get_syntax: ;enter with al=character. ;don't change any other registers. ;exit with al=syntax of that character. push bx mov bx,ss:syntax_table cmp bx,NIL je get_syntax_3 push ax mov ax,ss:name_length[bx] lea bx,size_form[bx] ;make bx->name. add bx,ax ;make bx->data. pop ax xlat ss:byte ptr .0 pop bx ret get_syntax_3: pop bx cmp al,'_' je get_syntax_1 cmp al,cr je get_syntax_2 cmp al,lf je get_syntax_2 cmp al,'0' jb get_syntax_0 cmp al,'9' jbe get_syntax_1 cmp al,'A' jb get_syntax_0 cmp al,'Z' jbe get_syntax_1 cmp al,'a' jb get_syntax_0 cmp al,'z' jbe get_syntax_1 get_syntax_0: mov al,0 ret get_syntax_1: mov al,1 ret get_syntax_2: mov al,2 ret ;code ends end