pagesize 86 HT equ 09h LF equ 0ah CR equ 0dh LINENEW equ CR+LF*256 ;the way a newline is stored in memory. TRAIL_BLANK equ 0FF01h ;special font characters TRAIL_TAB equ 0FF02h MORE_CHAR equ 0FF03h NEWLINE_CHAR equ 0FF04h include bufseg.a86 ;buffer definitions data dseg word public public w1, w2, this_point, this_row, other_row, topbotpercent public botpercent, toppercent, firstlimit, lastlimit, overwrite_row public overwrite_col, screen_column, window, inversed, inverse_mark public showblanks ;pointrow contains the row that the cursor is currently on, relative to the ; screen boundaries. Pointrow may be negative if the point is above the screen, ; or it may be larger than max_screen_line if the point is below the screen. w1 rs 0 w1_windseg rw 1 w1_pointrow rw 1 w1_firstline rb 1 w1_lastline rb 1 w1_firstpossible rb 1 w1_lastpossible rb 1 w1_firstcolumn rw 1 w2 rs 0 w2_windseg rw 1 w2_pointrow rw 1 w2_firstline rb 1 w2_lastline rb 1 w2_firstpossible rb 1 w2_lastpossible rb 1 w2_firstcolumn rw 1 pointrow equ word ptr .2 firstline equ byte ptr .4 lastline equ byte ptr .5 firstpossible equ byte ptr .6 lastpossible equ byte ptr .7 firstcolumn equ word ptr .8 this_point rw 1 ;->point in the current file. this_row rw 1 ;row of point on screen. other_row rw 1 ;row of point in other window. topbotpercent rw 0 botpercent rb 1 toppercent rb 1 firstlastlimits rw 0 firstlimit rb 1 lastlimit rb 1 public next_redisp_line next_redisp_line dw 0 public overwrite_flag overwrite_flag db 0 ;=0 if not overwriting. overwrite_rowcol rw 0 overwrite_row db 0 overwrite_col db 0 ;the following externs are in the computer-dependent file extrn max_screen_line: byte ;the following externs are in 'buffers' extrn textseg: word screen_column rw 1 ;window contains a list of which lines should be moved where, and which ; lines need to be redrawn. If an entry is positive, then the line which is ; currently at x belongs at window[x]. If an entry is TRASHED, it ; should be redrawn. ;inversed contains a list of which lines currently show inverse video. window rb 50 ;50 is > max_screen_line inversed rb 50 ;. . public inversing inversing dw 0 inverse_mark rw 1 public inverse_flag inverse_flag db 0 ;=0 means no inversing. TRASHED equ -1 ;note that TRASHED must be negative. showblanks db 0 byte_ptr rb 0 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 the computer-dependent file. extrn clear_to_eol: near extrn xychrout: near extrn chroutput: near extrn hardware_roll_up: near extrn hardware_roll_down: near extrn hardware_del_line: near extrn hardware_ins_line: near extrn position_cursor: near extrn xyputch: near ;the following externs are in 'memory' extrn compute_cursor?: near extrn set_line?: near ;the following externs are in 'buffers' extrn succ_buffer: near extrn buffer_number: near ;enter with bx=paragraph of buffer. ;exit with ax=number of buffer. extrn buffer_allocate: near extrn find_buffer: near ;enter with cx=buffer number. ;exit with nc, dx set to that buffer if it exists, cy otherwise. ;the following externs are in 'marks' extrn read_mark?: near extrn goto_mark?: near extrn get_split_mark: near extrn get_mark: near extrn split_at_point: near extrn set_mark_si: near extrn set_mark: near extrn stack_marks: near extrn goto_mark: near public read_panes read_panes: ret public read_current_window read_current_window: mov ax,1 ! cmp w2_windseg,0 ;no window 2 - must be 1. jz read_current_window_1 mov bl,w1_firstline ! cmp bl,w2_firstline jb read_current_window_1 inc ax read_current_window_1: ret public store_current_window store_current_window: cmp ax,1 ! jne store_current_window_1 cmp w2_windseg,0 ;is there a second window? je store_current_window_2 ;no - don't swap. mov al,w1_firstline ! cmp al,w2_firstline jb store_current_window_2 call swap_other_row ! call swap_windows jmps store_current_window_2 store_current_window_1: cmp ax,2 ! jne store_current_window_2 cmp w2_windseg,0 ;is there a second window? je store_current_window_2 ;no - don't swap. mov al,w1_firstline ! cmp al,w2_firstline ja store_current_window_2 call swap_other_row ! call swap_windows store_current_window_2: ret swap_other_row: mov ax,w1_windseg ;are we in the other window? cmp ax,w2_windseg jne swap_other_row_1 ;no - no worries. push w1_pointrow ;remember what other_row will be. mov ax,1 ! call stack_marks mov ax,'*'*256+'0' ! call set_mark ;0 := * mov ax,'.'*256+'*' ! call set_mark ;* := . mov al,'0' ! call goto_mark ;. := 0 mov ax,0 ! call stack_marks pop other_row swap_other_row_1: ret public read_other_window read_other_window: mov bx,w2_windseg or bx,bx ! je read_other_window_1 call buffer_number ! ret read_other_window_1: xor ax,ax ! ret public store_other_window store_other_window: ;enter with ax=buffer segment to show. mov cx,ax ;do they want one window? jcxz store_other_window_3 ;yes. call find_buffer ;find the buffer. jc store_other_window_3 ;can't find it - give them one window. cmp w2_windseg,0 ;do we have another window to set? jne store_other_window_1 ;yes - just set it. push dx ! call split_screen ! pop dx store_other_window_1: cmp dx,w2_windseg ;is it already showing? je store_other_window_2 ;yes - they're being silly. mov w2_windseg,dx ;show the buffer here. cmp w1_windseg,dx ;is this buffer also in w1? jne store_other_window_4 ;no - no worries. mov ax,w1_pointrow ;the place that the this window is at mov other_row,ax ; becomes the other row. mov ax,'.'*256+'*' ;set the split mark to the point. call set_mark store_other_window_4: mov bl,w2_firstline ;trash what's there. mov al,w2_lastline call trash_some_lines store_other_window_2: ret store_other_window_3: mov w2_windseg,0 mov al,max_screen_line ;fill the screen with this window. mov w1_lastline,al mov w1_firstline,0 mov si,offset w1 call set_window_percent call paint_screen ret split_screen: mov al,max_screen_line mov w2_lastline,al sar al,1 ! dec al mov w1_lastline,al add al,2 mov w2_firstline,al mov si,offset w1 call set_window_percent mov si,offset w2 call set_window_percent call paint_screen ret public store_panes store_panes: ret public store_showblanks store_showblanks: cmp showblanks,al ;are we changing it? mov showblanks,al ;store it in any case. je store_showblanks_1 ;if we changed it, paint the window. call paint_window store_showblanks_1: ret public read_showblanks read_showblanks: mov al,showblanks ! ret public read_firstline read_firstline: mov al,w1_firstline ! ret public read_lastline read_lastline: mov al,w1_lastline ! ret public read_newrow read_newrow: mov ax,w1_pointrow ! ret public read_firstcolumn read_firstcolumn: mov ax,w1_firstcolumn ! ret public read_top_percent read_top_percent: mov al,toppercent ! ret public read_bot_percent read_bot_percent: mov al,botpercent ! ret public store_top_percent store_top_percent: mov toppercent,al mov si,offset w1 call set_window_percent ret public store_bot_percent store_bot_percent: mov botpercent,al mov si,offset w1 call set_window_percent ret public init_screen init_screen: xor al,al mov w1_firstline,al mov w1_firstpossible,al mov al,max_screen_line ;fill the screen with this window. mov w1_lastline,al mov w1_lastpossible,al mov w1_firstcolumn,0 mov ax,textseg mov w1_windseg,ax ret public gotoxy gotoxy: cmp dl,max_screen_line ;is max_screen_line ok? jbe gotoxy_1 ;yes. mov dl,max_screen_line ;no - take min(dl, max_screen_line) gotoxy_1: cmp dh,79 ;are we on the screen? jbe gotoxy_2 mov dh,79 ;no - take min(dh, 79) gotoxy_2: mov overwrite_rowcol,dx ret public chrout chrout: ;enter with ax=char to "type" on screen. ;preserve si. mov dx,overwrite_rowcol cmp overwrite_flag,0 ;are we already overwriting? jne chrout_1 ;yes. mov overwrite_flag,1 ;say that we're overwriting mov window+0,TRASHED ;trash the first line. call position_cursor ;place to first character chrout_1: cmp al,CR ;go to left margin? jne chrout_4 call clear_to_eol ;yes - clear to end here. mov dh,0 jmp chrout_posc chrout_4: cmp al,LF ;go down a line? jne chrout_5 inc dl cmp dl,max_screen_line ;are we past the last line? jbe chrout_posc ;no. call hardware_roll_up ;yes - roll the screen up. mov dl,max_screen_line ;say on the last line. jmps chrout_posc chrout_5: cmp al,HT jne chrout_8 chrout_9: mov ah,0 mov al,' ' call chrout_putch test dh,7 jnz chrout_9 jmps chrout_exit chrout_8: call chrout_putch chrout_exit: mov overwrite_rowcol,dx ;remember where we are. ret chrout_posc: mov overwrite_rowcol,dx jmp position_cursor ;fall thru chrout_putch: mov bh,0 ;trash the line. mov bl,dl mov window[bx],TRASHED call chroutput ;print char at current cursor position inc dh ret public redisplay redisplay: mov ax,textseg ;is the current buffer showing in w1? cmp ax,w1_windseg je redisplay?_1 ;yes - all ok. xchg w1_windseg,ax ;no - put it in this window. cmp ax,w2_windseg ;was the old w1 showing in w2? jne redisplay?_2 ;no - nothing special. push ds mov ds,w2_windseg mov al,'*' ;yes - make the split mark the point call goto_mark? pop ds redisplay?_2: mov bl,w1_firstline mov al,w1_lastline call trash_some_lines mov ax,w1_windseg ;is this buffer also in w2? cmp ax,w2_windseg jne redisplay?_1 ;no - no worries. mov bl,w2_firstline ;yes - trash one line so that mov bh,0 ; the point is recomputed. hack, hack. mov window[bx],TRASHED mov ax,w2_pointrow ;the place that the other window is at mov other_row,ax ; becomes the other row. mov ax,'.'*256+'*' ;set the split mark to the point. call set_mark redisplay?_1: mov overwrite_flag,0 ;no longer overwriting. mov dx,0 ;start in the upper left hand corner mov overwrite_rowcol,dx ; the next time we overwrite. ;-------------- if 0 mov dx,0*256+24 ;dh=column, dl=row. mov si,offset window rd_0: lodsb ! add al,'A' call xychrout ! inc dh cmp dh,25 ! jb rd_0 mov si,offset inversed rd_1: lodsb ! add al,'0' call xychrout ! inc dh cmp dh,48 ! jb rd_1 endif ;-------------- push ds mov ds,w1_windseg ;*** assume ds:bufseg mov si,topbot mov es:this_point,si mov ax,es:next_redisp_line call force_point_into_window mov ax,es:w1_pointrow mov es:this_row,ax call redraw_trashed mov ax,es:this_row mov es:w1_pointrow,ax pop ds ;*** assume ds:data mov dx,screen_column sub dx,w1_firstcolumn mov dh,dl mov dl,byte ptr w1_pointrow call position_cursor cmp w2_windseg,0 ;is there a second window? je redisplay_one ;no. call swap_windows push ds mov ax,w1_windseg ;are they the same file? cmp ax,w2_windseg mov ds,ax ;really w2_ ;*** assume ds:bufseg jne redisplay__2 ;two windows into the same buffer. call get_split_mark ;get the split mark. cmp si,bottop ;are we at the point? jne redisplay__1 ;no. mov si,topbot ;yes - always use the top point. redisplay__1: mov es:this_point,si mov ax,es:other_row ;get the row in the other window. mov es:this_row,ax call redraw_trashed mov ax,es:this_row xchg es:other_row,ax sub ax,es:other_row ;how much did we adjust it by? sub es:w1_pointrow,ax ;adjust pointrow, too. jmps redisplay__3 redisplay__2: ;two windows, two buffers. mov si,topbot mov es:this_point,si xor ax,ax call force_point_into_window mov ax,es:w1_pointrow mov es:this_row,ax call redraw_trashed redisplay__3: call swap_windows pop ds ;*** assume ds:data redisplay_one: mov next_redisp_line,0 ;no more desired line 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 public adjust_buffers adjust_buffers: ;enter with ds,bx=old buffer paragraph, ax=new buffer paragraph. ;exit with all registers undisturbed! cmp es:w1_windseg,bx ;are we changing w1? jne adjust_buffers_1 mov es:w1_windseg,ax adjust_buffers_1: cmp es:w2_windseg,bx ;are we changing w2? jne adjust_buffers_2 mov es:w2_windseg,ax adjust_buffers_2: ret set_window_percent: ;note that set_window_percent doesn't use ds. ;enter with si->window to set. mov cl,100 mov ch,es:lastline[si] sub ch,es:firstline[si] inc ch mov al,es:toppercent mul ch div cl cmp al,ch jb set_window_percent_1 xor al,al set_window_percent_1: add al,es:firstline[si] mov es:firstpossible[si],al mov al,es:botpercent mul ch div cl mov ch,es:lastline[si] sub ch,al jae set_window_percent_2 mov ch,es:lastline[si] set_window_percent_2: mov es:lastpossible[si],ch ret roll_window_down_2_j_1: jmp roll_window_down_2 roll_window_down_5_j_1: jmp roll_window_down_5 roll_window_down: ;roll the window down until pointrow is in the window. mov al,es:firstlimit cbw cmp es:w1_pointrow,ax ;if pointrow>=firstlimit, we don't jge roll_window_down_2_j_1 ; need to roll down. ;Are there any lines now on the screen that will remain? Go if not. mov cx,es:w1_pointrow mov bh,0 mov bl,es:w1_lastline add cx,bx mov bl,es:w1_firstline sub cx,bx mov bl,es:firstlimit cmp cx,bx jl roll_window_down_5_j_1 ;we have to repaint the entire window. mov dx,es:w1_pointrow mov cl,es:w1_firstline mov ch,0 sub dx,cx inc dx ;now compute the number of times we need to roll. mov cx,es:w1_pointrow sub cx,bx mov es:w1_pointrow,bx ;bx is firstlimit neg cx ;Can we use the hardware scroll? Go if not. cmp es:w1_firstline,0 jne roll_window_down_3 mov al,es:max_screen_line cmp es:w1_lastline,al jne roll_window_down_3 ;Use the hardware scroll unless there isn't one. xchg cx,dx ;get the distance to skip call skip_to_line mov cx,dx roll_window_down_4: call hardware_roll_down jc roll_window_down_3 ;can't hardware roll. ;now adjust window[] for the change we just made to the screen. mov bl,es:w1_firstline mov bh,0 mov al,es:window[bx] ;save the current values for later. mov ah,es:inversed[bx] push ax push si call redraw_compare ;remember if we're inversing here. mov es:inversed[bx],al call redraw_line call remember_redrawn pop si call prevline mov es:window[bx],bl ;remember that this line is real. pop ax ;restore the old values. roll_window_down_6: cmp al,TRASHED ;is this a trashed line? je roll_window_down_7 inc al ;no - say that the line's moved up. cmp al,es:max_screen_line ;did it roll off the screen? jbe roll_window_down_7 ;no. mov al,TRASHED ;yes - it's gone. roll_window_down_7: inc bl xchg al,es:window[bx] xchg ah,es:inversed[bx] cmp bl,es:w1_lastline jb roll_window_down_6 loop roll_window_down_4 jmps roll_window_down_2 ;repaint screen. roll_window_down_5: call center_this jmps roll_window_down_2 ;Use software scroll. All we do is roll the window array. roll_window_down_3: mov bl,es:w1_firstline mov bh,0 mov al,es:window[bx] ;save the current value for later. mov ah,es:inversed[bx] mov es:window[bx],TRASHED roll_window_down_1: inc bl xchg al,es:window[bx] xchg ah,es:inversed[bx] cmp bl,es:w1_lastline jb roll_window_down_1 loop roll_window_down_3 roll_window_down_2: ret roll_window_up_2_j_1: jmp roll_window_up_2 roll_window_up: mov al,es:lastlimit cbw cmp es:w1_pointrow,ax ;if pointrow<=lastlimit, we don't jle roll_window_up_2_j_1 ; need to roll up. ;compute: pointrow-(lastline-firstline) > lastlimit ;Are there any lines now on the screen that will remain? Go if not. mov cx,es:w1_pointrow mov bh,0 mov bl,es:w1_firstline add cx,bx mov bl,es:w1_lastline sub cx,bx mov bl,es:lastlimit cmp cx,bx jg roll_window_up_5 ;we have to repaint the entire window. mov dx,es:w1_pointrow mov cl,es:w1_lastline mov ch,0 sub dx,cx dec dx ;now compute the number of times we need to roll. mov cx,es:w1_pointrow sub cx,bx mov es:w1_pointrow,bx ;bx is lastlimit. ;Can we use hardware scroll? Go if not. cmp es:w1_firstline,0 jne roll_window_up_3 mov al,es:max_screen_line cmp es:w1_lastline,al jne roll_window_up_3 ;Use the hardware scroll unless there isn't one. xchg cx,dx ;get the distance to skip call skip_to_line mov cx,dx roll_window_up_4: call hardware_roll_up jc roll_window_up_3 ;can't hardware roll. ;now adjust window[] for the change we just made to the screen. mov bl,es:w1_lastline mov bh,0 mov al,es:window[bx] ;save the current values for later. mov ah,es:inversed[bx] push ax call redraw_compare ;remember if we're inversing here. mov es:inversed[bx],al call redraw_line call remember_redrawn mov es:window[bx],bl ;remember that this line is real. pop ax ;restore old values. roll_window_up_6: cmp al,TRASHED ;has this line been trashed? je roll_window_up_7 dec al ;no - say the line's been moved. roll_window_up_7: dec bl xchg al,es:window[bx] xchg ah,es:inversed[bx] cmp bl,es:w1_firstline ja roll_window_up_6 loop roll_window_up_4 jmps roll_window_up_2 ;repaint screen. roll_window_up_5: call center_this jmps roll_window_up_2 ;Use software scroll. All we do is roll the window array. roll_window_up_3: mov bl,es:w1_lastline mov bh,0 mov al,es:window[bx] ;save the current value for later. mov ah,es:inversed[bx] mov es:window[bx],TRASHED roll_window_up_1: dec bl xchg al,es:window[bx] xchg ah,es:inversed[bx] cmp bl,es:w1_firstline ja roll_window_up_1 loop roll_window_up_3 roll_window_up_2: ret ;enter with pointrow=current relative screen line ;exit with a line inserted before pointrow. public window_insert window_insert: push si mov ax,ds ;is this in window 1? cmp ax,es:w1_windseg jne window_insert_1 mov si,offset w1 call window_ins window_insert_1: mov ax,ds ;is this in window 2? cmp ax,es:w2_windseg jne window_insert_2 mov si,offset w2 call window_ins window_insert_2: mov ax,ds ;are we showing in both windows? cmp ax,es:w1_windseg jne window_insert_3 cmp ax,es:w2_windseg jne window_insert_3 call split_at_point ;is the split mark at or after the point? jnc window_insert_3 ;no inc es:other_row ;yes - must increment the other row. window_insert_3: pop si ret ;private subroutine, called by window_insert to insert a line in a window. ;enter with si-> a window structure. window_ins: mov bx,es:pointrow[si] mov al,es:firstline[si] cbw ! cmp bx,ax ;are we above the screen? jl window_ins_3 ;yes - exit. mov al,es:lastline[si] cmp bx,ax ;are we below the screen? jg window_ins_2 ;yes - go down a row. mov al,es:lastline[si] call hardware_del_line ;delete last line in window lea ax,1[bx] call hardware_ins_line ;insert new line after point line mov al,TRASHED mov es:window[bx],al ;TRASH the point line jmps window_ins_4 ; and the new line window_ins_1: xchg al,es:window[bx] inc al ! jnz $+4 ! dec al ;beware of trashed lined xchg ah,es:inversed[bx] window_ins_4: inc bl cmp bl,es:lastline[si] jbe window_ins_1 window_ins_2: inc es:pointrow[si] window_ins_3: ret ;enter with pointrow=current relative screen line ;exit with the line at pointrow deleted. public window_delete window_delete: push si ! mov ax,ds ;is this in window 1? cmp ax,es:w1_windseg jne window_delete_1 mov si,offset w1 call window_del window_delete_1: mov ax,ds ;is this in window 2? cmp ax,es:w2_windseg jne window_delete_2 mov si,offset w2 call window_del window_delete_2: mov ax,ds ;are we showing in both windows? cmp ax,es:w1_windseg jne window_delete_3 cmp ax,es:w2_windseg jne window_delete_3 call split_at_point ;is the split mark at or after the point? jnc window_delete_3 ;no dec es:other_row ;yes - must decrement the other row. window_delete_3: pop si ! ret ;private subroutine, called by window_delete to delete a line from a window. ;enter with si-> a window structure. window_del: mov bx,es:pointrow[si] mov al,es:firstline[si] cbw ! cmp bx,ax ;are we above the screen? jl window_del_4 ;yes. mov al,es:lastline[si] cbw ! cmp bx,ax ;are we below the screen? jg window_del_1 ;yes. ;*CR* mov es:window[bx],TRASHED ;kill the line the cursor is on. mov al,bl call hardware_del_line mov al,es:lastline[si] call hardware_ins_line jmps window_del_5 ;go into while...do loop window_del_4: inc es:pointrow[si] jmps window_del_1 window_del_3: mov al,es:window+1[bx] ! dec al mov ah,es:inversed+1[bx] mov es:window[bx],al mov es:inversed[bx],ah window_del_5: inc bl cmp bl,es:lastline[si] jb window_del_3 mov es:window[bx],TRASHED ;kill lastline window_del_1: ret public trash_line trash_line: ;destroy the line that the point is on if it's also in the window. mov ax,ds ;is this in window 1? cmp ax,es:w1_windseg jne trash_line_1 mov si,offset w1 call trash_line_0 trash_line_1: mov ax,ds ;is this in window 2? cmp ax,es:w2_windseg jne trash_line_2 mov si,offset w2 call trash_line_0 trash_line_2: ret ;enter with si-> a window structure. trash_line_0: mov bx,es:pointrow[si] mov al,es:firstline[si] cbw ! cmp bx,ax jl trash_line_3 mov al,es:lastline[si] cbw ! cmp bx,ax jg trash_line_3 mov es:window[bx],TRASHED trash_line_3: ret public up_lines up_lines: mov ax,ds ;is this in window 2? cmp ax,es:w1_windseg jne up_lines_1 sub es:w1_pointrow,bx up_lines_1: mov ax,ds ;is this in window 2? cmp ax,es:w2_windseg jne up_lines_2 sub es:w2_pointrow,bx up_lines_2: ret public down_lines down_lines: mov ax,ds ;is this in window 1? cmp ax,es:w1_windseg jne down_lines_1 add es:w1_pointrow,bx down_lines_1: mov ax,ds ;is this in window 2? cmp ax,es:w2_windseg jne down_lines_2 add es:w2_pointrow,bx down_lines_2: ret public paint_screen paint_screen: ;note that paint doesn't use ds. ;what's on the screen is garbage. ;preserve si, dx. mov bl,0 mov al,es:max_screen_line call trash_some_lines ret center_window: ;note that center doesn't use ds. ;preserve dx. center_this: mov cl,es:w1_lastline ;compute the middle of the screen. sub cl,es:w1_firstline sar cl,1 add cl,es:w1_firstline mov ch,0 mov es:w1_pointrow,cx mov bl,es:w1_firstline mov al,es:w1_lastline call trash_some_lines ret public paint_window paint_window: ;preserve dx. mov ax,es:textseg cmp ax,es:w1_windseg jne paint_window_1 mov bl,es:w1_firstline mov al,es:w1_lastline call trash_some_lines paint_window_1: mov ax,es:textseg cmp ax,es:w2_windseg jne paint_window_2 mov bl,es:w2_firstline mov al,es:w2_lastline call trash_some_lines paint_window_2: ret trash_some_lines: ;enter with bl=first line to destroy, al=last line. ;preserve si, dx. mov es:w1_firstcolumn,0 ;go to the first column. mov bh,0 trash_some_lines_0: mov es:window[bx],TRASHED inc bl cmp bl,al jbe trash_some_lines_0 mov al,es:w1_firstpossible ;ensure that we're not above the screen. cbw cmp es:w1_pointrow,ax jge trash_some_lines_1 ;we're not. mov es:w1_pointrow,ax trash_some_lines_1: mov al,es:w1_lastpossible ;ensure that we're not below the screen. cbw cmp es:w1_pointrow,ax jle trash_some_lines_2 ;we're not. mov w1_pointrow,ax trash_some_lines_2: ret ;swap the two window data structures. swap_windows: mov si,offset w1 ! mov di,offset w2 mov cx,(offset w2)-(offset w1) swap_windows_0: mov al,es:[si] xchg al,es:[di] mov es:[si],al inc si ! inc di loop swap_windows_0 ret force_point_into_window: ;enter with al=the desired row, =0 if we don't care. ;***************************************************************************** ;* roll the window array until pointrow is on the screen. ;* when we roll the array, the lines we roll in must be repainted. ;* for example, assume: screen is 0..23 ;* if pointrow is 5, then we're done. ;* if pointrow is -7, then we must roll down 7 lines. ;* if pointrow is <=-24, then we must roll down 24 lines, which says that the ;* entire screen will be repainted. ;* if pointrow is 27, then we must roll up 3 lines. ;* if pointrow is >=48, then we must roll up 24 lines, which says that the ;* entire screen will be repainted. ;***************************************************************************** mov bl,es:w1_firstpossible mov bh,es:w1_lastpossible or al,al ;do we have a desired row? je redisplay_1 ;no. dec al cmp al,bl ;above firstpossible? ja redisplay_0 ;yes - ok. mov al,bl ;no - clip to firstpossible. redisplay_0: cmp al,bh ;below lastpossible? jb redisplay_00 ;yes - ok. mov al,bh ;no - clip to lastpossible. redisplay_00: mov bl,al mov bh,al redisplay_1: mov es:firstlastlimits,bx ;now truncate firstlimit if we can't get there. mov al,es:firstlimit cbw ;compute the number of display lines sub al,es:w1_firstline ; desired before the cursor line. cmp ax,linesbefore ;is it even possible to get there? jb redisplay_2 ;yes - just do it. mov ax,linesbefore ;no - truncate firstlimit to add al,es:w1_firstline ; the largest possible. mov es:firstlimit,al redisplay_2: ;Now update row,col call compute_cursor? mov es:screen_column,dx sub dx,es:w1_firstcolumn ;are we to the left of the screen? jb redisplay_01 ;yes - must roll the screen right. cmp dx,80 ;are we on the screen? jb redisplay_02 ;yes - we don't have the roll left. ;roll the window to the left. ;Eventually, we'll be smart about all this and really scroll the screen. ;For now, we'll repaint the screen every time we roll. ; jmps redisplay_02 redisplay_01: ;roll the window to the right. ;Eventually, we'll be smart about all this and really scroll the screen. ;For now, we'll repaint the screen every time we roll. add dx,es:w1_firstcolumn ;restore the cursor position. mov bl,es:w1_firstline mov al,es:w1_lastline call trash_some_lines and dl,not 7 ;back up to previous tab stop. sub dx,40 ;put the cursor in middle of screen. jae redisplay_03 mov dx,0 ;column is less than 40. redisplay_03: mov es:w1_firstcolumn,dx ;that is where we start redisplaying....................... redisplay_02: ;now roll the screen up or down, as needed. call roll_window_down call roll_window_up ret redraw_trashed: ;redraw all changed lines if there are any to redraw. redraw_trashed_4: mov bl,es:w1_firstline mov bh,0 mov dh,0 ;initially, we don't need to redraw any. redraw_trashed_3: mov dl,es:window[bx] ;get new window contents. or dh,dl ;remember if we need to redraw any. or dl,dl ;if positive, it's a line to be moved. js redraw_trashed_5 ;if negative, skip it. cmp dl,bl ;is the line already there? je redraw_trashed_5 ;yes - skip it. mov es:window[bx],TRASHED or dh,TRASHED redraw_trashed_5: inc bl cmp bl,es:w1_lastline jbe redraw_trashed_3 cmp es:inverse_flag,0 ;if we're inversing, we might need to redraw. jne redraw_trashed_1 or dh,dh ;do we need to redraw any lines? jns redraw_trashed_9 ;no. redraw_trashed_1: mov bl,es:w1_firstline mov bh,0 mov cx,es:this_row ;get the row that the point is on. sub cx,bx call skip_to_line ;find the first line on the screen. call redraw_anyway ;see if we need to redraw anyway. redraw_trashed_7: call redraw_compare ;remember if we're inversing here. mov es:inversed[bx],al cmp es:window[bx],0 jns redraw_trashed_a ;if negative, redraw it. call redraw_line mov es:window[bx],bl ;remember that this line is drawn. redraw_trashed_a: call remember_redrawn inc bl cmp bl,es:w1_lastline jbe redraw_trashed_7 redraw_trashed_9: mov es:inversing,0 ;say that we're not inversing. ret remember_redrawn: ;enter with si->text, bx=screen line. ;exit with si->next line. call nextline shl es:inversed[bx],1 shl es:inversed[bx],1 call redraw_compare or es:inversed[bx],al ret redraw_anyway: ;preserve si,bx. cmp es:inverse_flag,0 je redraw_anyway_1 push si push bx redraw_anyway_2: call redraw_compare push ax call nextline ;see if this line contains the mark or point. call redraw_compare pop cx mov ch,cl ;save a copy. xor cl,al ;see if the bits changed. test cl,1 ;is the point in this line? jne redraw_anyway_yes ;yes - must redraw. shl ch,1 shl ch,1 or al,ch ;make up the compare byte. cmp al,es:inversed[bx] ;have they changed? je redraw_anyway_no ;no - don't necessarily redraw. redraw_anyway_yes: mov es:window[bx],TRASHED ;say that this line is gone. redraw_anyway_no: inc bl cmp bl,es:w1_lastline jbe redraw_anyway_2 pop bx pop si redraw_anyway_1: ret redraw_compare: ;enter with si->text buffer. ;exit with al and 1 = 1 if si beginning of desired line. ;don't destroy dx. mov si,es:this_point ;get the point. or cx,cx ;is cx negative? js skip_to_line_4 ;yes - we have to move forward. cmp word ptr (-2)[si],LINENEW ;if we're not at the beginning of je skip_to_line_3 ; this line, backup to beginning. call prevline skip_to_line_3: jcxz skip_to_line_2 skip_to_line_1: call prevline loopne skip_to_line_1 jne skip_to_line_2 ;did we hit the beginning? inc cx ;yes - restore the count. sub es:this_row,cx ;adjust this row. jmps skip_to_line_2 skip_to_line_4: neg cx ;make cx into a positive count. ;cx is at least one. skip_to_line_5: call nextline loopne skip_to_line_5 skip_to_line_2: mov al,es:inverse_flag ;are we inversing? cmp al,0 je skip_to_line_6 ;no. push bx ! push dx ! push si call get_mark ;the mark is in inverse_flag mov es:inverse_mark,si ;remember where the inverse mark is. pop si ! pop dx ! pop bx skip_to_line_6: ret redraw_line: ;enter with si -> line to be redrawn, bl=row of line. ;paint from firstcolumn for 80 columns. ;this routine is intense. ;preserve cx, bx call redraw_set ! xor di,di ;start at column zero. mov dh,0 ! mov dl,bl call position_cursor ! mov bl,-1;start without trailing blanks. cmp si,botbot ;are we at bottom already? je redraw_line_9_j_1 ;yes - clear to eol. redraw_line_2: call redraw_pointer ! mov ax,[si] cmp ax,LINENEW ;done with line? je redraw_line_3 ;yes - exit. inc si ! cmp dh,79 ;at right hand column? ja redraw_line_d ;yes - don't print. cmp di,es:w1_firstcolumn ;before first column? jb redraw_line_4 ;yes - just compute new column. cmp al,' ' ;possible trailing blanks. je redraw_line_a cmp al,HT jne redraw_line_b ;not trailing blanks - forget. redraw_line_a: cmp bl,-1 ;are we already remembering? jne redraw_line_c ;yes - don't remember again. mov bl,dh ;found a trailing blank character, mov bp,si ; remember where it was. jmps redraw_line_c redraw_line_b: mov bl,-1 ;printable char - forget trailing blanks. redraw_line_c: call xy_char_put ! jmps redraw_line_2 redraw_line_d: cmp dh,80 ;did we just get there? ja redraw_line_2 ;no. dec dh ! mov ax,MORE_CHAR ;yes - print the "more" symbol. call xychrout ! mov dh,81 ;say that we're in the next column. jmps redraw_line_2 redraw_line_4: inc di ! cmp al,HT ;only tabs are special jne redraw_line_2 mov ax,di ! add ax,7 ;round up to next tab stop. and al,not 7 ! mov di,ax jmps redraw_line_2 redraw_line_9_j_1: jmps redraw_line_9 redraw_line_3: cmp es:showblanks,0 ;should we show blanks? je redraw_line_8 cmp bl,-1 ;are there any trailing blanks? je redraw_line_8 ;no. mov dh,bl ;restore the column. xchg si,bp ;save the current and restore the old. dec si call redraw_set redraw_line_7: call redraw_pointer ! mov ax,[si] ;get the next char. cmp ax,LINENEW ! je redraw_line_e cmp dh,79 ! ja redraw_line_e inc si ! cmp al,' ' ;it can only be a tab or a space. je redraw_line_6 ;must be a space. redraw_line_5: mov ax,TRAIL_TAB ;output a trailing tab char. call xychrout inc dh ! test dh,7 ;at a tab stop yet? jne redraw_line_5 ;no. jmp redraw_line_7 redraw_line_6: ;output a trailing blank char. mov ax,TRAIL_BLANK call xychrout inc dh jmp redraw_line_7 redraw_line_e: mov si,bp ;restore the text pointer. redraw_line_8: cmp dh,80 ;put a newline symbol if there's room. jae redraw_line_9 cmp es:inversing,0 ;only if we're inversing. je redraw_line_9 mov ax,NEWLINE_CHAR ;newline symbol. call xychrout inc dh redraw_line_9: call clear_to_eol mov bh,0 ! mov bl,dl ;restore bx. ret redraw_pointer: ;adjust si from the top to the bottom if necessary, and adjust inversing. cmp si,topbot ;at the point yet? jne redraw_pointer_1 ;no. mov si,bottop cmp es:inverse_flag,0 ;are we inversing? je redraw_pointer_1 ;no. not es:inversing ;say that we've passed the point. redraw_pointer_1: cmp si,es:inverse_mark ;are we at the inverse mark? jne redraw_pointer_2 ;yes - maybe inverse. cmp es:inverse_flag,0 ;are we inversing? je redraw_pointer_2 ;no. not es:inversing ;say that we've passed the point. redraw_pointer_2: ret redraw_set: cmp es:inverse_flag,0 ;if we're not inversing, don't inverse. je redraw_set_1 call redraw_compare cmp si,es:inverse_mark ;are we exactly at the mark? jne redraw_set_2 ;no - just check parity. xor al,2 ;yes - flip the associated bit. redraw_set_2: mov es:inversing,0 ;say that we're not inversing. or al,al ;look for 00,11 or 10,01 jpe redraw_set_1 ;go if not within point and mark. not es:inversing ;say that we're inversing. redraw_set_1: ret xy_char_put: ;put a char on the screen. Interpret tabs. cmp al,HT ! jne xy_char_put_1 xy_char_put_2: mov al,' ' ! call xy_char_put_1 test dh,7 ! jnz xy_char_put_2 ret xy_char_put_1: mov ah,0 ! call chroutput inc dh ! ret public prevline prevline: ;retreat si to the previous line. ;return zr if si->beginning of file (and leave si alone) ;return nz otherwise. ;are we at the beginning of the file already? cmp si,toptop ! je prevline_beginning ;yes - exit. ;where are we in the file? cmp si,topbot ! jbe prevline_before ;at, before or after the point? prevline_after: dec si ! cmp si,bottop ;have we reached the top of the bottom? je prevline_at ;yes - drop down to prevline_before. cmp word ptr 0fffeh[si],LINENEW ;at the beginning of a new line? jne prevline_after ;no - keep looking. dec si ;did we just find a non-real newline? cmp si,bottop ;if we did, then si is now at bottop je prevline_at ; and we need to keep searching. inc si ;restore si and exit. jmps prevline_exit prevline_at: mov si,topbot ;start searching at the bottom inc si ; of the top. prevline_before: dec si cmp word ptr 0fffeh[si],LINENEW ;at the beginning of a new line? jne prevline_before ;no - keep looking. prevline_exit: or si,si ;return nz prevline_beginning: ret public nextline nextline: ;advance si to the next line. ;return zr if si->end of file (and leave si alone) ;return nz otherwise. cmp si,topbot ! jne nextline_1 mov si,bottop nextline_1: cmp si,botbot ! je nextline_2 cmp word ptr [si],LINENEW ! je nextline_3 inc si ! jmps nextline nextline_3: inc si ! inc si ! or si,si ! ret nextline_2: push ax ! xor ax,ax ! pop ax ! ret public compute_one compute_one: cmp al,HT ! jne compute_one_1 and dl,0f8h ! add dx,008h ! ret compute_one_1: inc dx ! ret end