home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
cpm86
/
fmacs86.ark
/
MARKS.A86
< prev
next >
Wrap
Text File
|
1989-02-09
|
13KB
|
560 lines
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