pagesize 86 v30 equ 0 test_device equ 0 cr equ 0dh lf equ 0ah if v30 ;macros for NEC V20/V30 or Intel 80186/286 codemacro SHRW parm:ew,count:db ;shift word right by db 0c1h ;immediate count modrm 5,parm db count endm endif ;CCPM function EQUs mc_max equ 35h mc_free equ 39h codemacro CCPM parm:db ;call CCPM db 0b1h ! db parm ;mov cl,parm db 0cdh ! db 0e0h ;int 0E0H endm include bufseg.a86 ;buffer definitions data dseg word public public textseg textseg dw 0ffffh ;segment of current buffer first_buffer dw 0ffffh ;segment of first buffer extrn inverse_flag: byte mcb rb 5 ;memory control block mcb_base equ word ptr mcb mcb_length equ word ptr mcb+2 mcb_ext equ byte ptr mcb+4 ;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, ss:data ;the following externs are in 'memory' extrn read_mark: near extrn del_to_mark: near ;the following externs are in 'redisplay' extrn redisplay: near extrn paint_screen: near extrn init_entry: near extrn uninit_exit: near extrn abort_fatal: near ;fatal error handler public get_next_buffer get_next_buffer: push ds mov ds,textseg ;*** assume ds:bufseg mov ax,next_buffer pop ds ;*** assume ds:data ret public buffer_allocate buffer_allocate: ;entry: ; case cx of ; -1..-32768: report the current buffer number. ; exit: ax=current buffer number. ; 0: create a new buffer. ; exit: ax=new buffer number if enough memory, ax=0 otherwise. ; 1..32767: ; entry: cx=buffer number to select, ax=0 for read/write buffer. ; exit: ax=buffer number if it exists, ax=0 otherwise. jcxz buffer_allocate_2 or cx,cx ! jns $+5 ;if cx<0, return buffer number. jmp buffer_allocate_7 ;****** select buffer ****** push cx push ax call find_buffer jc buffer_allocate_1 ;buffer not found. push ds push dx mov ds,dx ;get the current buffer back. call select_buffer pop dx pop ds pop cx ;pushed as ax =0 if read/write buffer. pop ax ;pushed as cx (buffer number). ret buffer_allocate_1: add sp,4 ;conserve the stack. mov ax,0 ;buffer not found. ret buffer_allocate_2: ;****** create a new buffer ****** mov mcb_length,1000h ;max. = 64K xor ax,ax ! mov mcb_base,ax mov mcb_ext,al mov dx,offset mcb ccpm mc_max ;allocate memory or al,al ! jnz buffer_allocate_3;no memory mov ax,bufseg_size+0fh if v30 shrw ax,4 else shl ax,1 ! shl ax,1 ! shl ax,1 ! shl ax,1 endif cmp mcb_length,ax ja buffer_allocate_4 ;there is enough memory mov mcb_ext,0 mov dx,offset mcb ccpm mc_free ;free this small memory block buffer_allocate_3: xor ax,ax ! ret ;error return buffer_allocate_4: mov ax,1 ! push es mov dx,first_buffer cmp dx,0ffffh jne buffer_allocate_5 mov cx,mcb_base mov first_buffer,cx jmps buffer_allocate_6 buffer_allocate_5: inc ax mov es,dx ! mov dx,es:next_buffer cmp dx,0ffffh ! jne buffer_allocate_5 mov cx,mcb_base mov es:next_buffer,cx buffer_allocate_6: mov cx,mcb_length mov es,mcb_base mov es:buffer_length,cx mov es:next_buffer,0ffffh pop es ! push ds ! push ax mov ds,mcb_base call init_vars? call init_marks call open_buffer pop ax ! pop ds ! ret buffer_allocate_7: ;****** return current buffer number ****** mov bx,ss:textseg call buffer_number ;return number in ax. ret public buffer_insert buffer_insert: ;enter with al=mark, cx=buffer number. ;insert the text between point and mark from the given buffer. ;exit with nc if ok, cy if the given buffer doesn't exist, or the specified ; text won't fit. push textseg push ax call find_buffer ;find their buffer. ;*** assume ds:bufseg jc buffer_insert_1 ;not found. push ds push dx mov ds,dx ;get the current buffer back. call select_buffer pop dx pop ds pop ax push dx call read_mark pop dx pop ds ;make ds->our buffer. push dx ;save ->their buffer. push cx call select_buffer pop cx pop ax ;pushed as dx. call insert_string? jmps buffer_insert_2 buffer_insert_1: add sp,4 ;get rid of mark, textseg. stc buffer_insert_2: push es ;restore ds. pop ds ;*** assume ds:data ret public buffer_number buffer_number: ;enter with bx=paragraph of buffer. ;exit with ax=number of buffer. push ds ;*** assume ds:bufseg mov dx,ss:first_buffer xor ax,ax buffer_number_1: inc ax mov ds,dx cmp dx,bx ;is this the one we're looking for. mov dx,next_buffer ;in any case, get the next buffer jne buffer_number_1 buffer_number_2: pop ds ;*** assume ds:data ret public succ_buffer succ_buffer: ;enter with bx=buffer number. ;exit with nc, bx=next nonempty buffer, dx=segment of next buffer, ; cy if no other buffers or all other buffers are empty. push ds mov cx,bx mov ax,bx mov dx,first_buffer ;*** assume ds:bufseg succ_buffer_2: cmp dx,0FFFh ;at the end? stc je succ_buffer_3 ;yes - don't change the buffer number. mov ds,dx mov dx,next_buffer loop succ_buffer_2 succ_buffer_0: cmp dx,0FFFFh ;are we at the end? jne succ_buffer_1 mov ds,first_buffer ;yes - start from the beginning again. mov dx,next_buffer ;skip the first buffer. mov ax,1 succ_buffer_1: inc ax ;preincrement. cmp ax,bx ;have we wrapped around? stc je succ_buffer_3 ;yes - exit. mov ds,dx ;get the new segment to try. mov dx,topbot ;is the next buffer empty? sub dx,toptop add dx,botbot sub dx,bottop mov dx,next_buffer je succ_buffer_0 ;yes - keep looking. mov bx,ax ;return the new buffer number. clc succ_buffer_3: mov dx,ds ;remember the segment. ;*** assume ds:data pop ds ret public find_buffer find_buffer: ;enter with cx=buffer number. ;exit with nc, dx set to that buffer if it exists, cy otherwise. mov dx,first_buffer ;*** assume ds:bufseg find_buffer_1: cmp dx,0FFFFh ;at the end? je find_buffer_2 mov ds,dx mov dx,next_buffer loop find_buffer_1 mov dx,ds ;get the current buffer back. push es pop ds clc ret find_buffer_2: push es ;restore the data segment. pop ds ;*** assume ds:data stc ret ;code ends code cseg 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 'memory' extrn init_vars?: near extrn insert_string?: near ;the following externs are in 'marks' extrn init_marks: near ;the following externs are in 'redisp' extrn adjust_buffers: near select_buffer: ;enter with ds=buffer to select. mov ss:textseg,ds ;save the new current buffer. mov ax,botbot sub ax,toptop mov dx,0 mov cx,100 div cx mov memsize,ax ret close_buffer: ;close the buffer in ds. mov ax,topbot ;if topbot<>bottop, then it's open. cmp ax,bottop je close_buffer_1 ;if it's already closed, we're done. mov di,topbot if 1 mov ax,ds ;if it's open and it's not the first cmp ax,ss:first_buffer ; buffer, close it. jne close_buffer_2 add di,2000 ;leave at most this many free bytes cmp di,bottop ; in buffer one. jae close_buffer_1 ;but if we can't leave that many, don't bother close_buffer_2: endif mov si,bottop mov bottop,di ;save the new bottop. mov cx,botbot sub cx,si ;same as sub cx,bottop add cx,2 ;include the trailing newline. push es push ds pop es rep movsb pop es sub di,2 ;don't include the newline in botbot. mov botbot,di close_buffer_1: ret open_buffer: ;select the buffer in ds. ;enter with ds=buffer to open. mov bx,buffer_length mov ax,ds mov di,bx add bx,ax ;make bx=first unused para. mov cl,04 ;change di from paras into bytes shl di,cl push es push ds pop es mov si,botbot std mov cx,botbot sub cx,bottop inc si dec di movsb ;move the LF mov botbot,di movsb ;move the CR rep movsb inc di mov bottop,di cld pop es call select_buffer ret buffer_paragraphs: ;compute the number of paragraphs used by a buffer. ;enter with ds=buffer ;exit with cx=number of paragraphs. mov cx,botbot add cx,0fh+2 ;round up to next paragraph plus two for newline rcr cx,1 ;ensure that 65536 bytes becomes shr cx,1 ; 1000h paragraphs. shr cx,1 shr cx,1 ret ;code ends end