home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-10-22 | 55.9 KB | 2,446 lines |
- Newsgroups: comp.sources.misc
- From: jmd@cyclone.bt.co.uk (John Downey)
- Subject: v33i015: xvi - portable multi-window vi-like editor, Part06/18
- Message-ID: <1992Oct23.181305.238@sparky.imd.sterling.com>
- X-Md4-Signature: 43bffc1302d05b2deead1f2dd5c9cda1
- Date: Fri, 23 Oct 1992 18:13:05 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: jmd@cyclone.bt.co.uk (John Downey)
- Posting-number: Volume 33, Issue 15
- Archive-name: xvi/part06
- Environment: Unix, MS-DOS, OS/2, QNX
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: xvi/src/ibmpc_a.asm xvi/src/screen.c
- # Wrapped by kent@sparky on Thu Oct 22 09:03:42 1992
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 6 (of 18)."'
- if test -f 'xvi/src/ibmpc_a.asm' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xvi/src/ibmpc_a.asm'\"
- else
- echo shar: Extracting \"'xvi/src/ibmpc_a.asm'\" \(19731 characters\)
- sed "s/^X//" >'xvi/src/ibmpc_a.asm' <<'END_OF_FILE'
- X; Copyright (c) 1990,1991,1992 Chris and John Downey
- X_TEXT segment word public 'CODE'
- X db "@(#)ibmpc_a.asm 2.1 (Chris & John Downey) 7/29/92"
- X db 0
- X_TEXT ends
- X
- X;***
- X;
- X; program name:
- X; xvi
- X; function:
- X; PD version of UNIX "vi" editor, with extensions.
- X; module name:
- X; ibmpc_a.asm
- X; module function:
- X; Assembly language part of terminal interface module for IBM PC
- X; compatibles running MS-DOS.
- X;
- X; This code has been assembled with Microsoft's Macro Assembler
- X; (MASM) version 5.1, & is compatible with code generated by
- X; MS-DOS C compilers using the normal large memory model calling
- X; conventions. This includes the Microsoft & Zortech compilers.
- X;
- X; If we're running on a mono system, or one with an EGA or VGA,
- X; & we were started in a text mode, we can achieve much faster
- X; display output by writing directly to the frame buffer; we can
- X; also save the previous screen contents & restore them when we
- X; exit or run a sub-shell, which can be useful. If we have a
- X; CGA, or we were started in a graphics mode, we just use the
- X; functions supplied by the PC BIOS, which are slower, but good
- X; enough for most purposes. On a modern 80386-based system, the
- X; difference in speed is hardly noticeable.
- X; history:
- X;
- X; STEVIE - ST Editor for VI Enthusiasts, Version 3.10
- X; Originally by Tim Thompson (twitch!tjt)
- X; Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
- X; Heavily modified by Chris & John Downey
- X;***
- X
- Xinclude 8086mm.inc
- X
- X;
- X; If SWAPSCREEN is defined, we attempt to save the previous screen
- X; image & restore it when we exit or run another process. If you don't
- X; want this to happen, just comment out the line below.
- X;
- XSWAPSCREEN equ 1
- X
- X;
- X; If you don't want mouse input handling, comment out the line below.
- X;
- XMOUSE equ 1
- X
- X C_extern _malloc
- X C_extern _cparams
- X
- X public _alert
- X public _erase_display
- X public _erase_line
- X public _flush_output
- X public _hidemouse
- X public _mousestatus
- X public _outchar
- X public _outstr
- X public _scroll_up
- X public _scroll_down
- X public _set_colour
- X public _showmouse
- X public _tty_endv
- X public _tty_goto
- X public _tty_open
- X public _tty_startv
- X
- X;
- X; Segment addresses for PC text mode frame buffer.
- X;
- XVMONOSEG = 0b000h ; Mono frame buffer.
- XVCOLOURSEG = 0b800h ; Colour frame buffer.
- X
- X;
- X; BIOS video functions.
- X;
- Xvbios macro ahval, alval
- X ifnb <ahval>
- X ifnb <alval>
- X mov ax, (ahval shl 8) + alval
- X else
- X mov ah, ahval
- X endif
- X endif
- X int 10h
- X endm
- X;
- X; BIOS video function numbers.
- X;
- XB_MOVECURSOR = 2 ; Move cursor.
- XB_UPSCROLL = 6 ; Scroll window up.
- XB_DOWNSCROLL = 7 ; Scroll window down.
- XB_WRITECHAR = 9 ; Write character & attribute at
- X ; current position.
- XB_TTYWRITE = 0eh ; Teletype-style write.
- XB_GETMODE = 0fh ; Get video mode.
- XB_SETPALETTE = 10h ; Set palette registers.
- XB_EGACGEN = 11h ; EGA character generator.
- XB_VCONFIG = 12h ; Video subsystem configuration.
- X
- X;
- X; Subfunction (of function 10h) for setting overscan register.
- X;
- XB_OVERSCAN = 1
- X
- X;
- X; Subfunctions for EGA character generator.
- X;
- XB_EGATEST = 30h
- XB_8X8FONT = 12h
- XB_8X14FONT = 11h
- X
- X;
- X; BIOS function to use alternate print screen routine.
- X;
- Xaltpscreen macro
- X mov bl, 20h
- X vbios B_VCONFIG
- X endm
- X
- X;
- X; BIOS function to get equipment list.
- X;
- Xbiosequip macro
- X int 11h
- X endm
- X;
- X; Value returned by biosequip (in ax) to indicate a mono display.
- X;
- XEQUIP_MONO = 30h
- X
- X;
- X; Default number of rows in text modes.
- X;
- XDEF_T_ROWS = 25
- X
- X;
- X; Video modes.
- X;
- XBWT25X80 = 2 ; 25 x 80 black & white (CGA) text.
- XCT25X80 = 3 ; 25 x 80 colour text.
- XMT25X80 = 7 ; 25 x 80 monochrome (MDA) text.
- X
- X;
- X; I/O ports.
- X;
- XTIMER_2 = 42h ; Timer channel 2.
- XTIMER_3 = 43h ; Timer channel 3.
- XPORT_B = 61h ; 8255 port B.
- X
- X;
- X; Interrupt used by Microsoft mouse driver.
- X;
- XMSMINT = 33h
- X
- X;
- X; Call mouse driver.
- X;
- Xmsmouse macro funcnum
- X ifnb <funcnum>
- X mov ax, funcnum
- X endif
- X int MSMINT
- X endm
- X;
- X; Mouse driver function numbers.
- X;
- XMSM_SHOW = 1
- XMSM_HIDE = 2
- XMSM_GETSTATUS = 3
- XMSM_SETYLIMITS = 8
- X
- X;
- X; Values for mouseflag.
- X;
- XMF_NOMOUSE = -1
- XMF_INITIAL = 0
- XMF_OK = 1
- XMF_VISIBLE = 2
- X
- X;
- X; Segment containing interrupt vector table.
- X;
- XINTVECTAB segment at 0
- X ;
- X ; Vector used by Microsoft mouse driver.
- X ;
- X org (MSMINT * 4)
- Xmsvecoff dw ?
- Xmsvecseg dw ?
- XINTVECTAB ends
- X
- X;
- X; BIOS variable data segment.
- X;
- XBVSEG = 40h
- X
- XBIOSDATA segment at BVSEG
- X ;
- X ; Low word of timer variable.
- X ;
- X org 6ch
- Xb_timer_low dw ?
- X ;
- X ; Variable giving number of screen rows - 1.
- X ;
- X org 84h
- Xb_rowsvar db ?
- XBIOSDATA ends
- X
- X_TEXT segment word public 'CODE'
- X assume nothing
- X assume cs: _TEXT
- X
- X even
- X ifdef SWAPSCREEN
- Xsaveptr label dword ; Pointer to saved screen image.
- Xsvboff dw 0
- Xsvbseg dw 0
- Xscrwords dw ? ; Number of 2-byte words in saved
- X ; screen image.
- X endif ; SWAPSCREEN
- Xvbase dw 0 ; Segment address of frame buffer. If
- X ; this is 0, we don't access the frame
- X ; buffer directly.
- Xvcolumn label byte
- Xvpos dw ? ; Virtual screen position.
- Xscrsize label word ; Screen dimensions.
- Xncolumns db ? ; Low byte of scrsize.
- Xnrows db ? ; High byte of scrsize.
- Xwritemethod dw offset bioswrite
- X ; Pointer to function we use for
- X ; outputting characters to the screen.
- Xstartmode db ?
- Xega db 0 ; Flag indicating presence of EGA/VGA.
- Xvcolour db ? ; Virtual colour.
- X ifdef MOUSE
- Xmouseflag db MF_INITIAL
- X ; This is changed by _tty_startv to
- X ; MF_OK if we have a mouse driver
- X ; installed, or MF_NOMOUSE if we
- X ; haven't.
- X else ; MOUSE
- Xmouseflag db MF_NOMOUSE
- X endif ; MOUSE
- X
- X ifdef SWAPSCREEN
- X ;
- X ; These routines deal with saving the previous screen image &
- X ; restoring it.
- X ;
- Xsavescreen:
- X cmp vbase, 0
- X je dontcopy
- X push si
- X push di
- X push ds
- X les di, saveptr
- X mov ax, es
- X or ax, di
- X jz cps_pop
- X mov ds, vbase
- X clear si
- X jmp short copyscreen
- X
- Xrestorescreen proc near
- X cmp vbase, 0
- X je dontcopy
- X push si
- X push di
- X push ds
- X mov es, vbase
- X clear di
- X lds si, saveptr
- X mov ax, ds
- X or ax, si
- X jz cps_pop
- Xcopyscreen:
- X mov cx, scrwords
- X cld
- X rep movsw
- Xcps_pop:
- X pop ds
- X pop di
- X pop si
- Xdontcopy:
- X ret
- Xrestorescreen endp
- X endif ; SWAPSCREEN
- X
- X even
- X_flush_output:
- X ;
- X ; void flush_output(void);
- X ;
- X ; Update real cursor position.
- X ;
- X push bp
- X mov dx, vpos
- X clear bh ; Display page 0.
- X vbios B_MOVECURSOR
- X pop bp
- X C_ret
- X
- X even
- X_erase_line:
- X ;
- X ; void erase_line(void);
- X ;
- X ; Erase to end of line.
- X ;
- X ; Don't update cursor position.
- X ;
- X mov cl, ncolumns ; Get width of screen.
- X mov al, vcolumn ; Get current column.
- X sub cl, al ; Number of spaces to write ...
- X jz noerase ; ... except if it's 0 ...
- X clear ch
- X mov al, ' '
- X cld
- X call [writemethod]
- Xnoerase:
- X C_ret
- X
- X_erase_display:
- X ;
- X ; void erase_display(void);
- X ;
- X ; Erase entire display by using BIOS scroll screen
- X ; function to scroll all the lines in the display.
- X ;
- X ; Don't update cursor position.
- X ;
- X call _cparams ; This is in ibmpc_c.c.
- X mov bh, al ; Get colour for blank screen.
- X push bp
- X clear cx ; Top left row & column (0).
- X mov al, nrows ; Number of lines (0).
- X mov dx, scrsize
- X dec dh ; Bottom right row.
- X dec dl ; Bottom right column.
- X vbios B_UPSCROLL
- X pop bp
- X C_ret
- X
- X even
- X_showmouse:
- X ;
- X ; void showmouse(void);
- X ;
- X ; Show mouse cursor.
- X ;
- X ; If we don't seem to have a mouse driver, or we think
- X ; the cursor is already visible, don't do anything.
- X ;
- X cmp mouseflag, MF_OK
- X jne m_invalid
- X mov ax, MSM_SHOW
- X mov mouseflag, MF_VISIBLE
- Xm_valid:
- X msmouse
- Xm_invalid:
- X C_ret
- X
- X even
- X_hidemouse:
- X ;
- X ; void hidemouse(void);
- X ;
- X ; Hide mouse cursor.
- X ;
- X ; If we don't seem to have a mouse driver, or we don't
- X ; think the cursor is visible, don't do anything.
- X ;
- X cmp mouseflag, MF_VISIBLE
- X jne m_invalid
- X mov ax, MSM_HIDE
- X mov mouseflag, MF_OK
- X jmp short m_valid
- X
- X_mousestatus:
- X ;
- X ; unsigned mousestatus(unsigned *xpos, unsigned *ypos);
- X ;
- X ; Return mouse button status, with current mouse
- X ; co-ordinates in *xpos & *ypos.
- X ;
- X push bp
- X mov bp, sp
- X cmp mouseflag, MF_OK
- X jge getstatus ; if it's MF_OK or MF_VISIBLE
- X clear ax ; Button status = 0.
- X cwd ; y co-ordinate = 0.
- X mov cx, ax ; x co-ordinate = 0.
- X jmp short ms_finish
- Xgetstatus:
- X msmouse MSM_GETSTATUS
- X mov ax, bx ; Return button status in ax.
- Xms_finish:
- X ;
- X ; Stack frame:
- X ;
- X ; bp + CPTRSIZE + DPTRSIZE + 2
- X ; ypos pointer
- X ;
- X ; bp + CPTRSIZE + 2
- X ; xpos pointer
- X ;
- X ; bp + 2 return address
- X ;
- X ; bp caller's bp
- X ;
- X if DPTRSIZE eq 4
- X push ds
- X endif
- X ptrasg <[bp + CPTRSIZE + 2]>, cx
- X ; x co-ordinate.
- X assume ds: nothing
- X ptrasg <[bp + CPTRSIZE + DPTRSIZE + 2]>, dx
- X ; y co-ordinate.
- X if DPTRSIZE eq 4
- X pop ds
- X endif
- X pop bp
- X C_ret
- X
- X_tty_open:
- X ;
- X ; void tty_open(unsigned int *prows, unsigned int *pcolumns);
- X ;
- X ; Initialize display. Parameters point to variables in
- X ; caller's default data segment giving dimensions of
- X ; screen. We also maintain our own record of these
- X ; values in scrsize, in this segment.
- X ;
- X push bp
- X push ds
- X mov ax, cs
- X mov ds, ax
- X assume ds: _TEXT
- X clear dx
- X mov bx, dx
- X vbios B_EGACGEN, B_EGATEST ; Do we have an EGA/VGA?
- X tst dl
- X jz notega
- X inc dl ; Yes: dl is number of rows - 1.
- X inc ega
- X jmp short testmode
- Xnotega:
- X mov dl, DEF_T_ROWS ; No: assume 25 rows.
- Xtestmode:
- X vbios B_GETMODE
- X mov bp, sp
- X mov cx, cs
- X ;
- X ; Register usage at this point:
- X ;
- X ; al current display mode
- X ; ah number of text columns
- X ; cx our code segment
- X ; dl number of text rows
- X ; bp pointer (relative to ss) to stack frame
- X ;
- X ; Stack frame:
- X ;
- X ; bp + CPTRSIZE + DPTRSIZE + 4
- X ; pointer to screen columns variable
- X ;
- X ; bp + CPTRSIZE + 4
- X ; pointer to screen rows variable
- X ;
- X ; bp + 4 return address
- X ;
- X ; bp + 2 caller's bp
- X ;
- X ; bp caller's ds
- X ;
- X mov ncolumns, ah
- X mov nrows, dl
- X if DPTRSIZE eq 2
- X mov ds, [bp]
- X assume ds: nothing
- X endif
- X clear dh ; Clear high byte of rows.
- X ptrasg <[bp + CPTRSIZE + 4]>, dx
- X ; Return rows to caller.
- X assume ds: nothing
- X mov dl, ah
- X ptrasg <[bp + CPTRSIZE + DPTRSIZE + 4]>, dx
- X mov ds, cx ; Point ds to our code segment again.
- X assume ds: _TEXT
- X mov startmode, al
- X cmp al, MT25X80 ; Mono text mode?
- X jne notmda
- X biosequip
- X and ax, EQUIP_MONO ; Is it a real mono system?
- X cmp ax, EQUIP_MONO
- X jne notmda ; No.
- X mov vbase, VMONOSEG
- X jmp short directvideo
- Xnotmda:
- X cmp al, CT25X80 ; Is it a graphics mode?
- X ja o_finish ; Yes.
- X cmp ega, 0 ; Do we have an EGA or VGA?
- X je o_finish ; No.
- X mov vbase, VCOLOURSEG
- Xdirectvideo:
- X mov writemethod, offset fastwrite
- X ifdef SWAPSCREEN
- X mov ax, scrsize
- X dec ah ; (number of rows - 1) ...
- X mul ah ; times (number of columns) ...
- X mov scrwords, ax ; = number of screen
- X ; characters to save ...
- X shl ax, 1 ; times 2 = number of bytes to save.
- X mov ds, [bp] ; Restore ds for C library.
- X assume ds: nothing
- X push ax
- X call _malloc
- X inc sp
- X inc sp
- X if DPTRSIZE eq 2
- X cwd ; if (ax == 0) dx = 0;
- X tst ax ; if (malloc() returned NULL) ...
- X jz dxok ; ... dx should also be 0.
- X mov dx, ds ; ds now points to C data segment,
- X ; not our code segment.
- Xdxok:
- X endif ; DPTRSIZE eq 2
- X mov svboff, ax
- X mov svbseg, dx
- X endif ; SWAPSCREEN
- Xo_finish:
- X pop ds
- X assume ds: nothing
- X pop bp
- X C_ret
- X
- X_tty_startv:
- X ;
- X ; void tty_startv();
- X ;
- X ; If we've run a child process, & the mode has
- X ; changed, we do our level best to restore it to what
- X ; it was before: otherwise we're in trouble because
- X ; the screen dimensions have probably changed.
- X ;
- X push bp
- X push ds
- X mov ax, cs
- X mov ds, ax
- X assume ds: _TEXT
- X vbios B_GETMODE
- X mov dx, scrsize
- X cmp al, startmode ; Has mode changed since we started?
- X jne changemode
- X cmp ah, dl ; Current number of columns is
- X ; in ah; check that it hasn't
- X ; changed.
- X je modeok ; It hasn't.
- Xchangemode:
- X mov al, startmode
- X clear ah ; Function 0 (set mode).
- X vbios
- X mov al, startmode
- Xmodeok:
- X cmp ega, 0
- X je sv_save
- X ;
- X ; If we have an EGA/VGA, the number of rows may have
- X ; changed even though the mode hasn't, because
- X ; fonts with different sizes can be loaded.
- X ;
- X cmp al, BWT25X80
- X je checkrows
- X cmp al, CT25X80
- X je checkrows
- X cmp al, MT25X80
- X jne sv_save
- Xcheckrows: ; Check number of rows.
- X mov ax, BVSEG
- X mov es, ax
- X assume es: BIOSDATA
- X mov al, b_rowsvar
- X inc al
- X cmp al, dh
- X jae sv_save
- X altpscreen
- X assume es: nothing
- X mov ax, (B_EGACGEN shl 8) + B_8X14FONT
- X ; Use default EGA font.
- X cmp dh, DEF_T_ROWS
- X jbe setegafont
- X mov ax, (B_EGACGEN shl 8) + B_8X8FONT
- X ; Use small font.
- Xsetegafont:
- X clear bl ; Table 0 in character generator RAM.
- X vbios
- Xsv_save:
- X ifdef SWAPSCREEN
- X call savescreen
- X endif ; SWAPSCREEN
- X ifdef MOUSE
- X cmp mouseflag, MF_INITIAL
- X js sv_finish ; MF_NOMOUSE?
- X jne mousereset ; MF_OK or MF_VISIBLE?
- X clear ax
- X mov es, ax
- X assume es: INTVECTAB
- X mov ax, msvecoff ; Check the actual interrupt
- X or ax, msvecseg ; vector for the mouse driver.
- X jz sv_nomouse ; If it's 0, we can't call it.
- Xmousereset:
- X assume es: nothing
- X clear ax ; Function 0 (initialize mouse
- X msmouse ; driver).
- X tst ax
- X jz sv_nomouse ; Failure.
- X mov mouseflag, MF_OK ; Success.
- X ;
- X ; Set vertical limits for mouse movement according to
- X ; the number of screen rows; apparently the Microsoft
- X ; driver sometimes gets this wrong.
- X ;
- X mov dl, nrows ; Let dx = (nrows - 1) * 8.
- X dec dl
- X clear dh
- X mov cl, 3
- X shl dx, cl
- X clear cx
- X msmouse MSM_SETYLIMITS
- X jmp short sv_finish
- Xsv_nomouse:
- X mov mouseflag, MF_NOMOUSE
- X endif ; MOUSE
- Xsv_finish:
- X pop ds
- X assume ds: nothing
- X pop bp
- X C_ret
- X
- X_tty_endv:
- X ;
- X ; void tty_endv();
- X ;
- X ; We're about to exit or run another process. Restore
- X ; previous screen if appropriate, update real cursor
- X ; position & reset mouse driver to its default state
- X ; if required.
- X ;
- X ifdef SWAPSCREEN
- X ;
- X ; At this stage, sys_endv() should have just gone to
- X ; the bottom line, set the colour to
- X ; Pn(P_systemcolour) & cleared the line. We shouldn't
- X ; disturb its work, so restorescreen just restores the
- X ; top (nrows - 1) lines. This is controlled by the
- X ; scrwords variable.
- X ;
- X call restorescreen
- X endif ; SWAPSCREEN
- X Cn_call _flush_output
- X cmp mouseflag, MF_INITIAL
- X jle ev_finish
- X clear ax
- X msmouse
- Xev_finish:
- X C_ret
- X
- X even
- X_tty_goto:
- X ;
- X ; void tty_goto(int row, int column);
- X ;
- X ; Change virtual screen position.
- X ;
- X mov bx, sp
- X mov ah, byte ptr ss:[bx + CPTRSIZE]
- X mov al, byte ptr ss:[bx + CPTRSIZE + 2]
- X mov vpos, ax
- X C_ret
- X
- X_set_colour:
- X ;
- X ; void set_colour(int colour);
- X ;
- X ; Change virtual screen colour.
- X ;
- X mov bx, sp
- X mov al, byte ptr ss:[bx + CPTRSIZE]
- X mov vcolour, al
- X C_ret
- X
- X;
- X; These two routines are functionally equivalent; they are only called
- X; by indirection through the "writemethod" pointer.
- X;
- X even
- Xfastwrite proc near
- X ;
- X ; Write single character, or a number of repetitions
- X ; of the same character, to the screen. Character is
- X ; in al, number of repetitions in cx.
- X ;
- X ; This writes directly to the text mode frame buffer.
- X ;
- X ; Note that:
- X ;
- X ; - the direction flag must be clear.
- X ;
- X ; - cx is destroyed.
- X ;
- X push di
- X mov es, vbase
- X mov dx, vpos ; Get offset into frame buffer.
- X mov bl, ncolumns
- X xchg ax, bx ; al is now number of columns;
- X ; bl is character to write ...
- X mul dh ; ax is now (current row *
- X ; number of columns) ...
- X clear dh
- X add ax, dx ; Add current column (dl).
- X shl ax, 1 ; Multiply by 2 to get word offset.
- X mov di, ax
- X mov al, bl ; Retrieve character to write.
- X mov ah, vcolour
- X rep stosw ; Do the actual copying.
- X pop di
- X ret
- Xfastwrite endp
- X
- X even
- Xbioswrite proc near
- X ;
- X ; Write single character, or a number of repetitions
- X ; of the same character, to the screen. Character is
- X ; in al, number of repetitions in cx.
- X ;
- X ; This uses the BIOS B_WRITECHAR function.
- X ;
- X push bp
- X clear bh ; Display page 0.
- X mov dx, vpos
- X push ax
- X vbios B_MOVECURSOR
- X pop ax
- X mov bl, vcolour
- X vbios B_WRITECHAR
- X pop bp
- X ret
- Xbioswrite endp
- X
- X even
- Xvpadjust proc near
- X ;
- X ; Adjust virtual cursor position.
- X ;
- X mov ax, scrsize
- X mov dx, vpos
- X inc dl ; Increment column.
- X cmp dl, al
- X jb adjust
- X clear dl ; Wrap round to next line.
- X inc dh
- X cmp dh, ah
- X jnb vpa_finish
- Xadjust:
- X mov vpos, dx
- Xvpa_finish:
- X ret
- Xvpadjust endp
- X
- X even
- X_outchar:
- X ;
- X ; void outchar(int character);
- X ;
- X ; Display one character.
- X ;
- X mov bx, sp
- X mov al, byte ptr ss:[bx + CPTRSIZE]
- X mov cx, 1
- X cld
- X call [writemethod]
- X call vpadjust
- X C_ret
- X
- X even
- X_outstr:
- X ;
- X ; void outstr(char *string);
- X ;
- X ; Display C string.
- X ;
- X mov bx, sp
- X push si
- X
- X if DPTRSIZE eq 4
- X push ds
- X lds si, ss:[bx + CPTRSIZE]
- X assume ds: nothing
- X else
- X mov si, [bx + CPTRSIZE]
- X endif
- X cld
- Xgetnextc:
- X lodsb ; Get next character in al.
- X tst al ; Are we at the terminating '\0'?
- X jz endstring
- X mov cx, 1
- X call [writemethod]
- X call vpadjust
- X jmp getnextc
- X even
- Xendstring:
- X if DPTRSIZE eq 4
- X pop ds
- X endif
- X pop si
- X C_ret
- X
- Xscrollah:
- X ;
- X ; void scroll_up(unsigned startline,
- X ; unsigned endline,
- X ; unsigned nlines);
- X ;
- X ; void scroll_down(unsigned startline,
- X ; unsigned endline,
- X ; unsigned nlines);
- X ;
- X push bp
- X mov bp, sp
- X mov al, byte ptr [bp + CPTRSIZE + 6]
- X ; Number of lines.
- X tst al ; If 0 lines ...
- X jz noscroll ; ... do nothing.
- X clear cl ; Top left column (0).
- X mov ch, byte ptr [bp + CPTRSIZE + 2]
- X ; Top left row.
- X mov dl, ncolumns ; Bottom right column.
- X dec dl
- X mov dh, byte ptr [bp + CPTRSIZE + 4]
- X ; Bottom right row.
- X mov bh, vcolour ; Colour for blank lines.
- X vbios
- Xnoscroll:
- X pop bp
- X C_ret
- X
- X_scroll_up:
- X ;
- X ; Scroll region of screen up.
- X ;
- X mov ah, B_UPSCROLL
- X jmp scrollah
- X
- X_scroll_down:
- X ;
- X ; Scroll region of screen down.
- X ;
- X mov ah, B_DOWNSCROLL
- X jmp scrollah
- X
- X_alert:
- X ;
- X ; void alert(void);
- X ;
- X call _cparams
- X ;
- X ; cparams() gives us the current text colour in al,
- X ; the status line colour in ah & a visual bell flag in
- X ; dx; if this is non-zero, we use a visual bell
- X ; instead of an audible bell.
- X ;
- X push bp
- X tst dx
- X pushf ; Save processor flags on stack.
- X ; Zero flag means use audible bell.
- X jz ab_on
- X ;
- X ; Visual bell. Set overscan colour to the background
- X ; component of the current text colour (or, if this is
- X ; black, the background component of the current
- X ; status line colour) temporarily.
- X ;
- X ; To get the backround component, we have to shift the
- X ; value right 4 bits.
- X ;
- X mov cl, 4
- X shr al, cl ; Get text background colour.
- X mov bh, al
- X tst al
- X jnz gotcolour ; Text background colour isn't black.
- X shr ah, cl ; Get status line background colour.
- X mov bh, ah
- Xgotcolour:
- X vbios B_SETPALETTE, B_OVERSCAN
- X jmp short asdelay
- Xab_on:
- X ;
- X ; Audible bell. Make speaker sound by programming the
- X ; timer chip & the 8255 directly.
- X ;
- X cli
- X mov dx, TIMER_3
- X mov al, 0b6h
- X out dx, al ; Select timer channel 2 mode.
- X dec dx
- X ;
- X ; Send frequency data to timer. This gives us a
- X ; frequency of about 2 kHz.
- X ;
- X mov al, 99h ; Low byte of timer interval.
- X out dx, al
- X mov al, 2 ; High byte of timer interval.
- X out dx, al
- X mov dx, PORT_B
- X in al, dx ; Get status of port B.
- X mov ah, al ; Store it in ah.
- X or al, 3
- X out dx, al ; Turn speaker on.
- X sti
- X ;
- X ; Delay for 3 clock ticks (about 1/9 - 1/6 sec.).
- X ;
- X ; Don't change ah or dx.
- X ;
- Xasdelay:
- X mov cx, 3
- X mov bx, BVSEG
- X mov es, bx
- X assume es: BIOSDATA
- Xtloop:
- X mov bx, b_timer_low
- Xwaittick:
- X cmp bx, b_timer_low
- X je waittick
- X loop tloop
- X ;
- X ; Delay loop has now finished.
- X ;
- X popf ; Retrieve flags from stack.
- X jz ab_off ; Zero flag means use audible bell.
- X clear bh ; Set border colour to black.
- X vbios B_SETPALETTE, B_OVERSCAN
- X jmp short ab_finish
- Xab_off:
- X mov al, ah ; Previous status of port B.
- X and al, not 3
- X out dx, al ; Turn speaker off.
- Xab_finish:
- X pop bp
- X assume es: nothing
- X C_ret
- X
- X_TEXT ends
- X end
- END_OF_FILE
- if test 19731 -ne `wc -c <'xvi/src/ibmpc_a.asm'`; then
- echo shar: \"'xvi/src/ibmpc_a.asm'\" unpacked with wrong size!
- fi
- # end of 'xvi/src/ibmpc_a.asm'
- fi
- if test -f 'xvi/src/screen.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xvi/src/screen.c'\"
- else
- echo shar: Extracting \"'xvi/src/screen.c'\" \(32878 characters\)
- sed "s/^X//" >'xvi/src/screen.c' <<'END_OF_FILE'
- X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
- X#ifndef lint
- Xstatic char *sccsid = "@(#)screen.c 2.3 (Chris & John Downey) 9/4/92";
- X#endif
- X
- X/***
- X
- X* program name:
- X xvi
- X* function:
- X PD version of UNIX "vi" editor, with extensions.
- X* module name:
- X screen.c
- X* module function:
- X Screen handling functions.
- X* history:
- X STEVIE - ST Editor for VI Enthusiasts, Version 3.10
- X Originally by Tim Thompson (twitch!tjt)
- X Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
- X Heavily modified by Chris & John Downey
- X
- X***/
- X
- X#include "xvi.h"
- X
- X/*
- X * Size of command buffer - we won't allow anything more
- X * to be typed when we get to this limit.
- X */
- X#define CMDSZ 80
- X
- X/*
- X * The following is used to optimise screen updating; we
- X * keep a record of the real screen state and compare it
- X * with the new version before actually doing any updating.
- X *
- X * The l_line part is guaranteed to be always null-terminated.
- X */
- Xtypedef struct line_struct {
- X char *l_line; /* storage for characters in line */
- X int l_used; /* number of bytes actually used */
- X unsigned int l_flags; /* information bits */
- X} Sline;
- X
- X/*
- X * Bit definitions for l_flags.
- X */
- X#define L_TEXT 0x01 /* is an ordinary text line */
- X#define L_MARKER 0x02 /* is a marker line ('@' or '~') */
- X#define L_DIRTY 0x04 /* has been modified */
- X#define L_MESSAGE 0x08 /* is a message line */
- X#define L_COMMAND 0x10 /* is a command line */
- X#define L_READONLY 0x20 /* message line for readonly buffer */
- X
- X#define L_STATUS (L_MESSAGE | L_COMMAND) /* is a status line */
- X
- Xstatic Sline *new_screen; /* screen being updated */
- Xstatic Sline *real_screen; /* state of real screen */
- X
- X/*
- X * Status line glitch handling.
- X *
- X * Some terminals leave a space when changing colour. The number of spaces
- X * left is returned by the v_colour_cost() method within the VirtScr, and
- X * stored in the colour_cost variable herein - this is not perfect, it should
- X * really be in the Xviwin structure, but what the hell.
- X *
- X * "st_spare_cols" is the number of columns which are not used at the
- X * end of the status line; this is to prevent wrapping on this line,
- X * as this can do strange things to some terminals.
- X */
- X
- Xstatic int colour_cost = 0;
- Xstatic int st_spare_cols = 1;
- X
- Xstatic int line_to_new P((Xviwin *, Line *, int, long));
- Xstatic void file_to_new P((Xviwin *));
- Xstatic void new_to_screen P((VirtScr *, int, int));
- Xstatic void do_sline P((Xviwin *));
- Xstatic void clrline P((int));
- X
- X/*
- X * This routine must be called to set up the screen memory -
- X * if it is not, we will probably get a core dump.
- X *
- X * Note that, at the moment, it must be called with a whole-screen
- X * window, i.e. the first window, and only that window, so that the
- X * nrows and ncols fields represent the whole screen.
- X */
- X/*ARGSUSED*/
- Xvoid
- Xinit_screen(win)
- XXviwin *win;
- X{
- X static char *real_area, *new_area;
- X register int count;
- X VirtScr *vs;
- X
- X vs = win->w_vs;
- X
- X colour_cost = VScolour_cost(vs);
- X st_spare_cols = 1 + (colour_cost * 2);
- X
- X /*
- X * If we're changing the size of the screen, free the old stuff.
- X */
- X if (real_screen != NULL) {
- X free((char *) real_screen);
- X free((char *) new_screen);
- X free(real_area);
- X free(new_area);
- X }
- X
- X /*
- X * Allocate space for the lines, and for the structure holding
- X * information about each line. Notice that we allocate an
- X * extra byte at the end of each line for null termination.
- X */
- X real_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
- X new_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
- X real_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
- X new_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
- X
- X if (real_screen == NULL || new_screen == NULL ||
- X real_area == NULL || new_area == NULL) {
- X /* What to do now? */
- X sys_exit(0);
- X }
- X
- X /*
- X * Now assign all the rows ...
- X */
- X for (count = 0; count < VSrows(vs); count++) {
- X register Sline *rp, *np;
- X register int offset;
- X
- X rp = &real_screen[count];
- X np = &new_screen[count];
- X
- X offset = count * (VScols(vs) + 1);
- X
- X rp->l_line = real_area + offset;
- X np->l_line = new_area + offset;
- X rp->l_line[0] = np->l_line[0] = '\0';
- X rp->l_used = np->l_used = 0;
- X rp->l_flags = np->l_flags = 0;
- X }
- X}
- X
- X/*
- X * Set the L_DIRTY bit for a given line in both real_screen &
- X * new_screen if the stored representations are in fact different:
- X * otherwise clear it.
- X */
- Xstatic void
- Xmark_dirty(row)
- X int row;
- X{
- X Sline *rp;
- X Sline *np;
- X int used;
- X
- X rp = &real_screen[row];
- X np = &new_screen[row];
- X if (
- X
- X (rp->l_flags & ~L_DIRTY) != (np->l_flags & ~L_DIRTY)
- X ||
- X (used = rp->l_used) != np->l_used
- X ||
- X strncmp(rp->l_line, np->l_line, used) != 0
- X ) {
- X /*
- X * The lines are different.
- X */
- X np->l_flags |= L_DIRTY;
- X rp->l_flags |= L_DIRTY;
- X } else {
- X rp->l_flags = (np->l_flags &= ~L_DIRTY);
- X }
- X}
- X
- X/*
- X * Transfer the specified window line into the "new" screen array, at
- X * the given row. Returns the number of screen lines taken up by the
- X * logical buffer line lp, or 0 if the line would not fit; this happens
- X * with longlines at the end of the screen. In this case, the lines
- X * which could not be displayed will have been marked with an '@'.
- X */
- Xstatic int
- Xline_to_new(window, lp, start_row, line)
- XXviwin *window;
- XLine *lp;
- Xint start_row;
- Xlong line;
- X{
- X register unsigned c; /* next character from file */
- X register Sline *curr_line; /* output line - used for efficiency */
- X register char *ltext; /* pointer to text of line */
- X register int curr_index; /* current index in line */
- X bool_t eoln; /* true when line is done */
- X char extra[MAX_TABSTOP];
- X /* Stack for extra characters. */
- X int nextra = 0; /* index into stack */
- X int srow, scol; /* current screen row and column */
- X int vcol; /* virtual column */
- X
- X ltext = lp->l_text;
- X srow = start_row;
- X scol = vcol = 0;
- X curr_line = &new_screen[srow];
- X curr_index = 0;
- X eoln = FALSE;
- X
- X if (Pb(P_number)) {
- X static Flexbuf ftmp;
- X
- X flexclear(&ftmp);
- X (void) lformat(&ftmp, NUM_FMT, line);
- X (void) strcpy(curr_line->l_line, flexgetstr(&ftmp));
- X scol += NUM_SIZE;
- X }
- X
- X while (!eoln) {
- X /*
- X * Get the next character to put on the screen.
- X */
- X
- X /*
- X * "extra" is a stack containing any extra characters
- X * we have to put on the screen - this is for chars
- X * which have a multi-character representation, and
- X * for the $ at end-of-line in list mode.
- X */
- X
- X if (nextra > 0) {
- X c = extra[--nextra];
- X } else {
- X unsigned n;
- X
- X c = (unsigned char) (ltext[curr_index++]);
- X
- X /*
- X * Deal with situations where it is not
- X * appropriate just to copy characters
- X * straight onto the screen.
- X */
- X if (c == '\0') {
- X
- X if (Pb(P_list)) {
- X /*
- X * Have to show a '$' sign in list mode.
- X */
- X extra[nextra++] = '\0';
- X c = '$';
- X }
- X
- X } else {
- X char *p;
- X
- X n = vischar((int) c, &p, vcol);
- X /*
- X * This is a bit paranoid assuming
- X * that Pn(P_tabstop) can never be
- X * greater than sizeof (extra), but
- X * so what.
- X */
- X if (nextra + n > sizeof extra)
- X n = (sizeof extra - nextra);
- X /*
- X * Stack the extra characters so that
- X * they appear in the right order.
- X */
- X while (n > 1) {
- X extra[nextra++] = p[--n];
- X }
- X c = p[0];
- X }
- X }
- X
- X if (c == '\0') {
- X /*
- X * End of line. Terminate it and finish.
- X */
- X eoln = TRUE;
- X curr_line->l_flags = L_TEXT;
- X curr_line->l_used = scol;
- X curr_line->l_line[scol] = '\0';
- X mark_dirty(srow);
- X break;
- X } else {
- X /*
- X * Sline folding.
- X */
- X if (scol >= window->w_ncols) {
- X curr_line->l_flags = L_TEXT;
- X curr_line->l_used = scol;
- X curr_line->l_line[scol] = '\0';
- X mark_dirty(srow);
- X srow += 1;
- X scol = 0;
- X curr_line = &new_screen[srow];
- X }
- X
- X if (srow >= window->w_cmdline) {
- X for (srow = start_row; srow < window->w_cmdline; srow++) {
- X curr_line = &new_screen[srow];
- X
- X curr_line->l_flags = L_MARKER;
- X curr_line->l_used = 1;
- X curr_line->l_line[0] = '@';
- X curr_line->l_line[1] = '\0';
- X mark_dirty(srow);
- X }
- X return(0);
- X }
- X
- X /*
- X * Store the character in new_screen.
- X */
- X curr_line->l_line[scol++] = c;
- X vcol++;
- X }
- X }
- X
- X return((srow - start_row) + 1);
- X}
- X
- X/*
- X * file_to_new()
- X *
- X * Based on the current value of topline, transfer a screenful
- X * of stuff from file to new_screen, and update botline.
- X */
- Xstatic void
- Xfile_to_new(win)
- Xregister Xviwin *win;
- X{
- X register int row;
- X register Line *line;
- X register Buffer *buffer;
- X long lnum;
- X
- X buffer = win->w_buffer;
- X row = win->w_winpos;
- X line = win->w_topline;
- X lnum = lineno(buffer, line);
- X
- X while (row < win->w_cmdline && line != buffer->b_lastline) {
- X int nlines;
- X
- X nlines = line_to_new(win, line, row, lnum);
- X if (nlines == 0) {
- X /*
- X * Make it look like we have updated
- X * all the screen lines, since they
- X * have '@' signs on them.
- X */
- X row = win->w_cmdline;
- X break;
- X } else {
- X row += nlines;
- X line = line->l_next;
- X lnum++;
- X }
- X }
- X
- X win->w_botline = line;
- X
- X /*
- X * If there are any lines remaining, fill them in
- X * with '~' characters.
- X */
- X for ( ; row < win->w_cmdline; row++) {
- X register Sline *curr_line;
- X
- X curr_line = &new_screen[row];
- X
- X curr_line->l_flags = L_MARKER;
- X curr_line->l_used = 1;
- X curr_line->l_line[0] = '~';
- X curr_line->l_line[1] = '\0';
- X mark_dirty(row);
- X }
- X}
- X
- X/*
- X * new_to_screen
- X *
- X * Transfer the contents of new_screen to the screen,
- X * starting at "start_row", for "nlines" lines,
- X * using real_screen to avoid unnecessary output.
- X */
- Xstatic void
- Xnew_to_screen(vs, start_row, nlines)
- XVirtScr *vs;
- Xint start_row;
- Xint nlines;
- X{
- X int row; /* current row */
- X int end_row; /* row after last one to be updated */
- X int columns;
- X
- X columns = VScols(vs);
- X
- X if (!(echo & e_CHARUPDATE)) {
- X return;
- X }
- X
- X end_row = start_row + nlines;
- X
- X VSset_colour(vs, Pn(P_colour));
- X
- X for (row = start_row; row < end_row; row++) {
- X register int ncol; /* current column in new_screen */
- X register Sline *new,
- X *real; /* pointers to current lines */
- X register unsigned nflags;
- X unsigned rflags; /* flags for current lines */
- X register char *ntextp,
- X *rtextp;
- X /* pointers to line text */
- X register int nc; /* current character in new_screen */
- X int n_used,
- X r_used;
- X
- X nflags = (new = &new_screen[row])->l_flags;
- X rflags = (real = &real_screen[row])->l_flags;
- X
- X /*
- X * If the real and new screens are both "clean",
- X * don't bother.
- X */
- X if (!((nflags & L_DIRTY) || (rflags & L_DIRTY))) {
- X continue;
- X }
- X
- X ntextp = new->l_line;
- X rtextp = real->l_line;
- X
- X n_used = new->l_used;
- X r_used = real->l_used;
- X
- X if ((nflags & L_MESSAGE) ||
- X (rflags & L_STATUS) != (nflags & L_STATUS)) {
- X /*
- X * If it's a message line, or its status (text line,
- X * command line or message line) has changed, and either
- X * the real line or the new line is "dirty", better update
- X * the whole thing; if any colour changes are required,
- X * the effects of cursor movements may not be predictable
- X * on some terminals.
- X */
- X VSgoto(vs, row, 0);
- X if (nflags & L_STATUS) {
- X VSset_colour(vs, (nflags & L_READONLY) ? Pn(P_roscolour) :
- X Pn(P_statuscolour));
- X }
- X if ((nc = ntextp[0]) != '\0') {
- X VSputc(vs, row, 0, nc);
- X }
- X /*
- X * For command lines, only the first character should be
- X * highlighted.
- X */
- X if (nflags & L_COMMAND) {
- X VSset_colour(vs, Pn(P_colour));
- X }
- X if (nc != '\0') {
- X VSwrite(vs, row, 1, &ntextp[1]);
- X }
- X
- X /*
- X * Clear the rest of the line, if
- X * there is any left to be cleared.
- X */
- X if (n_used < columns) {
- X VSclear_line(vs, row, n_used);
- X }
- X
- X /*
- X * Change back to text colour if we have to.
- X */
- X if ((nflags & L_MESSAGE) != 0) {
- X VSset_colour(vs, Pn(P_colour));
- X }
- X
- X (void) strncpy(rtextp, ntextp, (int) (columns - st_spare_cols));
- X } else {
- X /*
- X * Look at each character in the line, comparing
- X * the new version with the one on the screen.
- X * If they differ, put it out.
- X *
- X * There is some optimisation here to avoid large
- X * use of tty_goto.
- X */
- X register int scol;
- X /* current column on physical screen */
- X register int last_ncol;
- X /* last column to be updated */
- X
- X for (ncol = scol = last_ncol = 0;
- X ncol < n_used && ncol < r_used;
- X (ncol++, scol++)) {
- X if ((nc = ntextp[ncol]) != rtextp[ncol]) {
- X /*
- X * They are different. Get to the right
- X * place before putting out the char.
- X */
- X if (ncol != 0) {
- X VSadvise(vs, row, last_ncol + 1,
- X ncol - last_ncol - 1,
- X ntextp + last_ncol + 1);
- X } else {
- X VSgoto(vs, row, scol);
- X /*
- X * A command line should have the first character
- X * - and only the first character - highlighted.
- X */
- X if (ncol == 0 && (nflags & L_STATUS) != 0) {
- X VSset_colour(vs, (nflags & L_READONLY) ?
- X Pn(P_roscolour) : Pn(P_statuscolour));
- X }
- X }
- X
- X VSputc(vs, row, ncol, nc);
- X
- X if (ncol == 0 && (nflags & L_COMMAND) != 0) {
- X VSset_colour(vs, Pn(P_colour));
- X }
- X last_ncol = ncol;
- X rtextp[ncol] = nc;
- X }
- X if (ncol == 0 && (nflags & L_COMMAND) != 0) {
- X scol += (colour_cost * 2);
- X }
- X }
- X
- X if (n_used > r_used) {
- X /*
- X * We have got to the end of the previous
- X * screen line; if there is anything left,
- X * we should just display it.
- X */
- X (void) strcpy(&rtextp[ncol], &ntextp[ncol]);
- X if (ncol == 0 && (nflags & L_COMMAND) != 0) {
- X /*
- X * A command line should have the first character
- X * - and only the first character - highlighted.
- X */
- X VSgoto(vs, row, 0);
- X VSset_colour(vs, Pn(P_statuscolour));
- X VSputc(vs, row, 0, ntextp[0]);
- X VSset_colour(vs, Pn(P_colour));
- X ncol = 1;
- X } else {
- X /*
- X * Skip over initial whitespace.
- X */
- X while (ntextp[ncol] == ' ') {
- X ncol++;
- X scol++;
- X }
- X }
- X if (ncol < columns)
- X VSwrite(vs, row, scol, &ntextp[ncol]);
- X } else if (r_used > n_used) {
- X /*
- X * We have got to the end of the new screen
- X * line, but the old one still has stuff on
- X * it. We must therefore clear it.
- X */
- X VSclear_line(vs, row, scol);
- X }
- X }
- X
- X real->l_line[n_used] = '\0';
- X real->l_used = n_used;
- X
- X /*
- X * The real screen line is a message or command line if the
- X * newly-updated one was. Otherwise, it isn't.
- X *
- X * Both the new and real screens may now be considered
- X * "clean".
- X */
- X real->l_flags = (
- X /*
- X * Turn these flags off first ...
- X */
- X (rflags & ~(L_STATUS | L_DIRTY))
- X /*
- X * ... then set whatever L_STATUS flags are
- X * set in new_screen.
- X */
- X | (nflags & L_STATUS)
- X );
- X new->l_flags &= ~L_DIRTY;
- X }
- X}
- X
- X/*
- X * Update the status line of the given window, and cause the status
- X * line to be written out. Note that we call new_to_screen() to cause
- X * the output to be generated; since there will be no other changes,
- X * only the status line will be changed on the screen.
- X */
- Xvoid
- Xupdate_sline(win)
- XXviwin *win;
- X{
- X do_sline(win);
- X new_to_screen(win->w_vs, (int) win->w_cmdline, 1);
- X VSflush(win->w_vs);
- X}
- X
- X/*
- X * Update the status line of the given window,
- X * from the one in win->w_statusline.
- X */
- Xstatic void
- Xdo_sline(win)
- XXviwin *win;
- X{
- X register char *from;
- X register char *to;
- X register char *end;
- X Sline *slp;
- X
- X from = flexgetstr(&win->w_statusline);
- X slp = &new_screen[win->w_cmdline];
- X to = slp->l_line;
- X end = to + win->w_ncols - st_spare_cols;
- X
- X while (*from != '\0' && to < end) {
- X *to++ = *from++;
- X }
- X
- X /*
- X * Fill with spaces, and null-terminate.
- X */
- X while (to < end) {
- X *to++ = ' ';
- X }
- X *to = '\0';
- X
- X slp->l_used = win->w_ncols - st_spare_cols;
- X slp->l_flags = L_MESSAGE;
- X if (is_readonly(win->w_buffer)) {
- X slp->l_flags |= L_READONLY;
- X }
- X mark_dirty(win->w_cmdline);
- X}
- X
- Xvoid
- Xupdate_cline(win)
- XXviwin *win;
- X{
- X Sline *clp;
- X unsigned width, maxwidth;
- X
- X clp = &new_screen[win->w_cmdline];
- X
- X maxwidth = win->w_ncols - st_spare_cols;
- X if ((width = flexlen(&win->w_statusline)) > maxwidth) {
- X width = maxwidth;
- X }
- X (void) strncpy(clp->l_line, flexgetstr(&win->w_statusline),
- X (int) width);
- X clp->l_used = width;
- X clp->l_line[width] = '\0';
- X clp->l_flags = (L_COMMAND | L_DIRTY);
- X /*
- X * We don't bother calling mark_dirty() here: it isn't worth
- X * it because the line's contents have almost certainly
- X * changed.
- X */
- X new_to_screen(win->w_vs, (int) win->w_cmdline, 1);
- X VSflush(win->w_vs);
- X}
- X
- X/*
- X * updateline() - update the line the cursor is on
- X *
- X * Updateline() is called after changes that only affect the line that
- X * the cursor is on. This improves performance tremendously for normal
- X * insert mode operation. The only thing we have to watch for is when
- X * the cursor line grows or shrinks around a row boundary. This means
- X * we have to repaint other parts of the screen appropriately.
- X */
- Xvoid
- Xupdateline(window)
- XXviwin *window;
- X{
- X Line *currline;
- X int nlines;
- X int curs_row;
- X
- X currline = window->w_cursor->p_line;
- X
- X /*
- X * Find out which screen line the cursor line starts on.
- X * This is not necessarily the same as window->w_row,
- X * because longlines are different.
- X */
- X if (plines(window, currline) > 1) {
- X curs_row = (int) cntplines(window, window->w_topline, currline);
- X } else {
- X curs_row = window->w_row;
- X }
- X
- X nlines = line_to_new(window, currline,
- X (int) (curs_row + window->w_winpos),
- X (long) lineno(window->w_buffer, currline));
- X
- X if (nlines != window->w_c_line_size) {
- X update_buffer(window->w_buffer);
- X } else {
- X new_to_screen(window->w_vs,
- X (int) (curs_row + window->w_winpos), nlines);
- X VSflush(window->w_vs);
- X }
- X}
- X
- X/*
- X * Completely update the representation of the given window.
- X */
- Xvoid
- Xupdate_window(window)
- XXviwin *window;
- X{
- X if (window->w_nrows > 1) {
- X file_to_new(window);
- X new_to_screen(window->w_vs,
- X (int) window->w_winpos, (int) window->w_nrows);
- X VSflush(window->w_vs);
- X }
- X}
- X
- X/*
- X * Update all windows.
- X */
- Xvoid
- Xupdate_all()
- X{
- X Xviwin *w = curwin;
- X
- X do {
- X if (w->w_nrows > 1) {
- X file_to_new(w);
- X }
- X if (w->w_nrows > 0) {
- X do_sline(w);
- X }
- X } while ((w = next_window(w)) != curwin);
- X
- X new_to_screen(w->w_vs, 0, (int) VSrows(w->w_vs));
- X VSflush(w->w_vs);
- X}
- X
- X/*
- X * Totally redraw the screen.
- X */
- Xvoid
- Xredraw_screen()
- X{
- X if (curwin != NULL) {
- X clear(curwin);
- X update_all();
- X }
- X}
- X
- Xvoid
- Xclear(win)
- XXviwin *win;
- X{
- X register int row;
- X int nrows;
- X
- X nrows = VSrows(win->w_vs);
- X
- X VSset_colour(win->w_vs, Pn(P_colour));
- X VSclear_all(win->w_vs);
- X
- X /*
- X * Clear the real screen lines, and mark them as modified.
- X */
- X for (row = 0; row < nrows; row++) {
- X clrline(row);
- X }
- X}
- X
- X/*
- X * The rest of the routines in this file perform screen manipulations.
- X * The given operation is performed physically on the screen. The
- X * corresponding change is also made to the internal screen image. In
- X * this way, the editor anticipates the effect of editing changes on
- X * the appearance of the screen. That way, when we call screenupdate a
- X * complete redraw isn't usually necessary. Another advantage is that
- X * we can keep adding code to anticipate screen changes, and in the
- X * meantime, everything still works.
- X */
- X
- X/*
- X * s_ins(win, row, nlines) - insert 'nlines' lines at 'row'
- X */
- Xvoid
- Xs_ins(win, row, nlines)
- XXviwin *win;
- Xregister int row;
- Xint nlines;
- X{
- X register int from, to;
- X int count;
- X VirtScr *vs;
- X
- X if (!(echo & e_SCROLL))
- X return;
- X
- X /*
- X * There's no point in scrolling more lines than there are
- X * (below row) in the window, or in scrolling 0 lines.
- X */
- X if (nlines == 0 || nlines + row >= win->w_nrows - 1)
- X return;
- X
- X /*
- X * The row specified is relative to the top of the window;
- X * add the appropriate offset to make it into a screen row.
- X */
- X row += win->w_winpos;
- X
- X /*
- X * Note that we avoid the use of 1-line scroll regions; these
- X * only ever occur at the bottom of a window, and it is better
- X * just to leave the line to be updated in the best way by
- X * update{line,screen}.
- X */
- X if (nlines == 1 && row + 1 == win->w_cmdline) {
- X return;
- X }
- X
- X vs = win->w_vs;
- X
- X if (vs->v_scroll != NULL) {
- X if (!VSscroll(vs, row, (int) win->w_cmdline - 1, -nlines)) {
- X /*
- X * Can't scroll what we were asked to - try scrolling
- X * the whole window including the status line.
- X */
- X VSclear_line(vs, (int) win->w_cmdline, 0);
- X clrline(win->w_cmdline);
- X if (!VSscroll(vs, row, (int) win->w_cmdline, -nlines)) {
- X /*
- X * Failed.
- X */
- X return;
- X }
- X }
- X } else {
- X return;
- X }
- X
- X /*
- X * Update the stored screen image so it matches what has
- X * happened on the screen.
- X */
- X
- X /*
- X * Move section of text down to the bottom.
- X *
- X * We do this by rearranging the pointers within the Slines,
- X * rather than copying the characters.
- X */
- X for (to = win->w_cmdline - 1, from = to - nlines; from >= row;
- X --from, --to) {
- X register char *temp;
- X
- X temp = real_screen[to].l_line;
- X real_screen[to].l_line = real_screen[from].l_line;
- X real_screen[from].l_line = temp;
- X real_screen[to].l_used = real_screen[from].l_used;
- X }
- X
- X /*
- X * Clear the newly inserted lines.
- X */
- X for (count = row; count < row + nlines; count++) {
- X clrline(count);
- X }
- X}
- X
- X/*
- X * s_del(win, row, nlines) - delete 'nlines' lines starting at 'row'.
- X */
- Xvoid
- Xs_del(win, row, nlines)
- Xregister Xviwin *win;
- Xint row;
- Xint nlines;
- X{
- X register int from, to;
- X int count;
- X VirtScr *vs;
- X
- X if (!(echo & e_SCROLL))
- X return;
- X
- X /*
- X * There's no point in scrolling more lines than there are
- X * (below row) in the window, or in scrolling 0 lines.
- X */
- X if (nlines == 0 || nlines + row >= win->w_nrows - 1)
- X return;
- X
- X /*
- X * The row specified is relative to the top of the window;
- X * add the appropriate offset to make it into a screen row.
- X */
- X row += win->w_winpos;
- X
- X /*
- X * We avoid the use of 1-line scroll regions, since they don't
- X * work with many terminals, especially if we are using
- X * (termcap) DO to scroll the region.
- X */
- X if (nlines == 1 && row + 1 == win->w_cmdline) {
- X return;
- X }
- X
- X vs = win->w_vs;
- X
- X if (vs->v_scroll != NULL) {
- X if (!VSscroll(vs, row, (int) win->w_cmdline - 1, nlines)) {
- X /*
- X * Can't scroll what we were asked to - try scrolling
- X * the whole window including the status line.
- X */
- X VSclear_line(vs, (int) win->w_cmdline, 0);
- X clrline(win->w_cmdline);
- X if (!VSscroll(vs, row, (int) win->w_cmdline, nlines)) {
- X /*
- X * Failed.
- X */
- X return;
- X }
- X }
- X } else {
- X return;
- X }
- X
- X /*
- X * Update the stored screen image so it matches what has
- X * happened on the screen.
- X */
- X
- X /*
- X * Move section of text up from the bottom.
- X *
- X * We do this by rearranging the pointers within the Slines,
- X * rather than copying the characters.
- X */
- X for (to = row, from = to + nlines;
- X from < win->w_cmdline;
- X from++, to++) {
- X register char *temp;
- X
- X temp = real_screen[to].l_line;
- X real_screen[to].l_line = real_screen[from].l_line;
- X real_screen[from].l_line = temp;
- X real_screen[to].l_used = real_screen[from].l_used;
- X }
- X
- X /*
- X * Clear the deleted lines.
- X */
- X for (count = win->w_cmdline - nlines; count < win->w_cmdline; count++) {
- X clrline(count);
- X }
- X}
- X
- X/*
- X * Insert a character at the cursor position, updating the screen as
- X * necessary. Note that this routine doesn't have to do anything, as
- X * the screen will eventually be correctly updated anyway; it's just
- X * here for speed of screen updating.
- X */
- Xvoid
- Xs_inschar(window, newchar)
- XXviwin *window;
- Xint newchar;
- X{
- X register char *curp;
- X register char *cp;
- X register char *sp;
- X Sline *rp;
- X Posn *pp;
- X VirtScr *vs; /* the VirtScr for this window */
- X char *newstr; /* printable string for newchar */
- X register unsigned nchars; /* number of chars in newstr */
- X unsigned currow;
- X unsigned curcol;
- X unsigned columns;
- X
- X vs = window->w_vs;
- X if (vs->v_insert == NULL)
- X return;
- X
- X if (!(echo & e_CHARUPDATE))
- X return;
- X
- X pp = window->w_cursor;
- X
- X /*
- X * If we are at (or near) the end of the line, it's not worth
- X * the bother. Define near as 0 or 1 characters to be moved.
- X */
- X cp = pp->p_line->l_text + pp->p_index;
- X if (*cp == '\0' || *(cp+1) == '\0')
- X return;
- X
- X curcol = window->w_col;
- X
- X /*
- X * If the cursor is on a longline, and not on the last actual
- X * screen line of that longline, we can't do it.
- X */
- X if (window->w_c_line_size > 1 && curcol != window->w_virtcol)
- X return;
- X
- X nchars = vischar(newchar, &newstr, curcol);
- X
- X /*
- X * And don't bother if we are (or will be) at the last screen column.
- X */
- X columns = window->w_ncols;
- X if (curcol + nchars >= columns)
- X return;
- X
- X /*
- X * Also, trying to push tabs rightwards doesn't work very
- X * well. It's usually better not to use the insert character
- X * sequence because in most cases we'll only have to update
- X * the line as far as the tab anyway.
- X */
- X if ((!Pb(P_list) && Pb(P_tabs)) && strchr(cp, '\t') != NULL) {
- X return;
- X }
- X
- X /*
- X * Okay, we can do it.
- X */
- X currow = window->w_row;
- X
- X VSinsert(vs, window->w_winpos + currow, curcol, newstr);
- X
- X /*
- X * Update real_screen.
- X */
- X rp = &real_screen[window->w_winpos + currow];
- X curp = &rp->l_line[curcol];
- X if ((rp->l_used += nchars) > columns)
- X rp->l_used = columns;
- X cp = &rp->l_line[rp->l_used - 1];
- X cp[1] = '\0';
- X if (cp - curp >= nchars)
- X {
- X sp = cp - nchars;
- X for (;;) {
- X *cp-- = *sp;
- X if (sp-- <= curp)
- X break;
- X }
- X }
- X
- X /*
- X * This is the string we've just inserted.
- X */
- X sp = newstr;
- X while (nchars-- > 0) {
- X *curp++ = *sp++;
- X }
- X}
- X
- Xvoid
- Xwind_goto(win)
- XXviwin *win;
- X{
- X VirtScr *vs;
- X
- X if (echo & e_CHARUPDATE) {
- X vs = win->w_vs;
- X VSgoto(vs, (int) win->w_winpos + win->w_row, win->w_col);
- X VSflush(vs);
- X }
- X}
- X
- Xstatic char inbuf[CMDSZ]; /* command input buffer */
- Xstatic unsigned int inpos = 0; /* posn of next input char */
- Xstatic unsigned char colposn[CMDSZ]; /* holds n chars per char */
- X
- X/*
- X * cmd_init(window, firstch)
- X *
- X * Initialise command line input.
- X */
- Xvoid
- Xcmd_init(win, firstch)
- XXviwin *win;
- Xint firstch;
- X{
- X if (inpos > 0) {
- X show_error(win, "Internal error: re-entered command line input mode");
- X return;
- X }
- X
- X State = CMDLINE;
- X
- X flexclear(&win->w_statusline);
- X (void) flexaddch(&win->w_statusline, firstch);
- X inbuf[0] = firstch;
- X inpos = 1;
- X update_cline(win);
- X colposn[0] = 0;
- X}
- X
- X/*
- X * cmd_input(window, character)
- X *
- X * Deal with command line input. Takes an input character and returns
- X * one of cmd_CANCEL (meaning they typed ESC or deleted past the
- X * prompt character), cmd_COMPLETE (indicating that the command has
- X * been completely input), or cmd_INCOMPLETE (indicating that command
- X * line is still the right mode to be in).
- X *
- X * Once cmd_COMPLETE has been returned, it is possible to call
- X * get_cmd(win) to obtain the command line.
- X */
- XCmd_State
- Xcmd_input(win, ch)
- XXviwin *win;
- Xint ch;
- X{
- X static bool_t literal_next = FALSE;
- X
- X if (!literal_next) {
- X switch (ch) {
- X case CTRL('V'):
- X literal_next = TRUE;
- X return(cmd_INCOMPLETE);
- X
- X case '\n': /* end of line */
- X case '\r':
- X inbuf[inpos] = '\0'; /* terminate input line */
- X inpos = 0;
- X State = NORMAL; /* return state to normal */
- X do_sline(win); /* line is now a message line */
- X return(cmd_COMPLETE); /* and indicate we are done */
- X
- X case '\b': /* backspace or delete */
- X case DEL:
- X {
- X unsigned len;
- X
- X inbuf[--inpos] = '\0';
- X len = colposn[inpos - 1] + 1;
- X while (flexlen(&win->w_statusline) > len)
- X (void) flexrmchar(&win->w_statusline);
- X update_cline(win);
- X if (inpos == 0) {
- X /*
- X * Deleted past first char;
- X * go back to normal mode.
- X */
- X State = NORMAL;
- X return(cmd_CANCEL);
- X }
- X return(cmd_INCOMPLETE);
- X }
- X
- X case '\033':
- X case EOF:
- X case CTRL('U'): /* line kill */
- X inpos = 1;
- X inbuf[1] = '\0';
- X flexclear(&win->w_statusline);
- X (void) flexaddch(&win->w_statusline, inbuf[0]);
- X update_cline(win);
- X return(cmd_INCOMPLETE);
- X
- X default:
- X break;
- X }
- X }
- X
- X literal_next = FALSE;
- X
- X if (inpos >= sizeof(inbuf) - 1) {
- X /*
- X * Must not overflow buffer.
- X */
- X beep(win);
- X } else {
- X unsigned curposn;
- X unsigned w;
- X char *p;
- X
- X curposn = colposn[inpos - 1];
- X w = vischar(ch, &p, (int) curposn);
- X if (curposn + w >= win->w_ncols - 1) {
- X beep(win);
- X } else {
- X colposn[inpos] = curposn + w;
- X inbuf[inpos++] = ch;
- X (void) lformat(&win->w_statusline, "%s", p);
- X update_cline(win);
- X }
- X }
- X
- X return(cmd_INCOMPLETE);
- X}
- X
- X/*ARGSUSED*/
- Xchar *
- Xget_cmd(win)
- XXviwin *win;
- X{
- X return(inbuf);
- X}
- X
- X/*ARGSUSED*/
- Xvoid
- Xgotocmd(win, clr)
- XXviwin *win;
- Xbool_t clr;
- X{
- X VirtScr *vs;
- X
- X vs = win->w_vs;
- X if (clr) {
- X VSclear_line(vs, (int) win->w_cmdline, 0);
- X }
- X VSgoto(vs, (int) win->w_cmdline, 0);
- X VSflush(vs);
- X}
- X
- X/*
- X * Display a prompt on the bottom line of the screen.
- X */
- Xvoid
- Xprompt(message)
- X char *message;
- X{
- X VirtScr *vs;
- X int row;
- X
- X vs = curwin->w_vs;
- X
- X row = VSrows(vs) - 1;
- X VSgoto(vs, row, 0);
- X VSset_colour(vs, Pn(P_statuscolour));
- X VSwrite(vs, row, 0, message);
- X VSset_colour(vs, Pn(P_colour));
- X VSgoto(vs, row, strlen(message));
- X VSflush(vs);
- X}
- X
- X/*
- X * Sound the alert.
- X */
- Xvoid
- Xbeep(window)
- Xregister Xviwin *window;
- X{
- X VSbeep(window->w_vs);
- X}
- X
- Xstatic char *(*disp_func) P((void));
- Xstatic int disp_colwidth;
- Xstatic int disp_maxcol;
- Xstatic bool_t disp_listmode;
- X
- X/*
- X * Start off "display" mode. The "func" argument is a function pointer
- X * which will be called to obtain each subsequent string to display.
- X * The function returns NULL when no more lines are available.
- X */
- Xvoid
- Xdisp_init(win, func, colwidth, listmode)
- XXviwin *win;
- Xchar *(*func) P((void));
- Xint colwidth;
- Xbool_t listmode;
- X{
- X State = DISPLAY;
- X disp_func = func;
- X if (colwidth > win->w_ncols)
- X colwidth = win->w_ncols;
- X disp_colwidth = colwidth;
- X disp_maxcol = (win->w_ncols / colwidth) * colwidth;
- X disp_listmode = listmode;
- X (void) disp_screen(win);
- X}
- X
- X/*
- X * Display text in glass-teletype mode, in approximately the style of
- X * the more(1) program.
- X *
- X * If the return value from (*disp_func)() is NULL, it means we've got
- X * to the end of the text to be displayed, so we wait for another key
- X * before redisplaying our editing screen.
- X */
- Xbool_t
- Xdisp_screen(win)
- XXviwin *win;
- X{
- X int row; /* current screen row */
- X int col; /* current screen column */
- X static bool_t finished = FALSE;
- X VirtScr *vs;
- X
- X vs = win->w_vs;
- X
- X if (finished || kbdintr) {
- X /*
- X * Clear the screen, and then ensure that the window
- X * on the current buffer is in the right place and
- X * updated; finally update the whole screen.
- X */
- X clear(win);
- X move_window_to_cursor(win);
- X update_all();
- X State = NORMAL;
- X finished = FALSE;
- X if (kbdintr) {
- X imessage = TRUE;
- X }
- X return(TRUE);
- X }
- X
- X VSclear_all(vs);
- X
- X for (col = 0; col < disp_maxcol; col += disp_colwidth) {
- X for (row = 0; row < VSrows(vs) - 1; row++) {
- X static char *line;
- X int width;
- X
- X if (line == NULL && (line = (*disp_func)()) == NULL) {
- X /*
- X * We've got to the end.
- X */
- X prompt("[Hit return to continue] ");
- X finished = TRUE;
- X return(FALSE);
- X }
- X
- X for (width = 0; *line != '\0'; line++) {
- X char *p;
- X unsigned w;
- X
- X w = vischar(*line, &p, disp_listmode ? -1 : width);
- X
- X if ((width += w) <= disp_colwidth) {
- X VSwrite(vs, row, col + width - w, p);
- X } else {
- X /*
- X * The line is too long, so we
- X * have to wrap around to the
- X * next screen line.
- X */
- X break;
- X }
- X }
- X
- X if (*line == '\0') {
- X if (disp_listmode) {
- X /*
- X * In list mode, we have to
- X * display a '$' to show the
- X * end of a line.
- X */
- X if (width < disp_colwidth) {
- X VSputc(vs, row, col + width, '$');
- X } else {
- X /*
- X * We have to wrap it
- X * to the next screen
- X * line.
- X */
- X continue;
- X }
- X }
- X /*
- X * If we're not in list mode, or we
- X * were able to display the '$', we've
- X * finished with this line.
- X */
- X line = NULL;
- X }
- X }
- X }
- X
- X prompt("[More] ");
- X
- X return(FALSE);
- X}
- X
- X/*
- X * Clear the given line, marking it as dirty.
- X */
- Xstatic void
- Xclrline(line)
- Xint line;
- X{
- X real_screen[line].l_used = 0;
- X real_screen[line].l_line[0] = '\0';
- X mark_dirty(line);
- X}
- END_OF_FILE
- if test 32878 -ne `wc -c <'xvi/src/screen.c'`; then
- echo shar: \"'xvi/src/screen.c'\" unpacked with wrong size!
- fi
- # end of 'xvi/src/screen.c'
- fi
- echo shar: End of archive 6 \(of 18\).
- cp /dev/null ark6isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 18 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-