Nansi.sys source code and support files
reintom at rocky2.UUCP
reintom at rocky2.UUCP
Fri Jul 18 23:30:58 AEST 1986
# ==================== cut here ====================
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# nansi.doc
# nansi.asm
# nansi_d.asm
# nansi_f.asm
# nansi_i.asm
# nansi_p.asm
# setraw.asm
# setraw.lc
# setraw.msc
# This archive created: Wed Jul 2 19:04:21 1986
export PATH; PATH=/bin:$PATH
if test -f 'nansi.doc'
then
echo shar: will not over-write existing file "'nansi.doc'"
else
cat << \SHAR_EOF > 'nansi.doc'
>From rna!cmcl2!harvard!topaz!dpz Sun Feb 6 01:28:16 206
Relay-Version: version B 2.10.1 6/24/83; site rocky2.UUCP
Path: rocky2!rna!cmcl2!harvard!topaz!dpz
From: dpz at topaz.RUTGERS.EDU (David P. Zimmerman)
Newsgroups: net.sources
Subject: NANSI.SYS docs
Message-ID: <4947 at topaz.RUTGERS.EDU>
Date: Sat, 10-May-86 21:46:09 EDT
Date-Received: Sun, 11-May-86 20:13:10 EDT
Organization: Rutgers Univ., New Brunswick, N.J.
Lines: 199
Keywords: rab oof
nansi - enhanced MS-DOS ansi console driver
SYNOPSIS
Include in \config.sys the line
device=nansi.sys
DESCRIPTION
Nansi.sys is a console driver which understands ANSI control
sequences. It has several advantages over ANSI.SYS (the driver
supplied with DOS):
1. It supports new escape sequences (see below).
2. It provides MUCH faster output under certain conditions.
3. It supports the 43-line mode of the EGA.
4. The darned bell is now 1/4 second instead of 1/2 second long.
What a console driver does:
When you, for example, type
C:> type foo.txt
COMMAND.COM opens the file foo.txt, reads it, and writes it to
the console driver, which puts it up on the screen.
Both ansi.sys and nansi.sys use IBM Video BIOS to control the screen.
However, nansi.sys bypasses BIOS if the screen is in a text mode; this
allows much faster operation under certain conditions.
While putting text up on the screen, (n)ansi.sys keeps a lookout for
the escape character (chr(27), known as ESC); this character signals
the start of a terminal control sequence.
Terminal control sequences follow the format
ESC [ param; param; ...; param cmd
where
ESC is the escape character chr$(27).
[ is the left bracket character.
param is an ASCII decimal number, or a string in quotes.
cmd is a case-specific letter identifying the command.
Usually, zero, one, or two parameters are given. If parameters
are omitted, they usually default to 1; however, some commands
(KKR and DKOCT) treat the no-parameter case specially.
Spaces are not allowed between parameters.
For example, both ESC[1;1H and ESC[H send the cursor to the home
position (1,1), which is the upper left.
Either single or double quotes may be used to quote a string.
Each character inside a quoted string is equivalent to one numeric
parameter. Quoted strings are normally used only for the Keyboard
Key Reassignment command.
Control Sequences
The following table lists the sequences understood by nansi.sys.
Differences between nansi.sys and the standard ansi.sys are marked
with a vertical bar (|).
Cursor Positioning
Short Long name Format Notes
CUP cursor position ESC[y;xH Sets cursor position.
HVP cursor position ESC[y;xf Same as CUP; not recommended.
CUU cursor up ESC[nA n = # of lines to move
CUD cursor down ESC[nB
CUF cursor forward ESC[nC n = # of columns to move
CUB cursor backward ESC[nD
DSR Device Status, Report! ESC[6n Find out cursor position.
CPR Cursor Position report ESC[y;xR Response to DSR, as if typed.
SCP Save Cursor Position ESC[s Not nestable.
RCP Restore Cursor Position ESC[u
Editing
ED Erase in Display ESC[2J Clears screen.
EL Erase in Line ESC[K Clears to end of line.
IL | Insert Lines ESC[nL Inserts n blank lines at cursor line.
DL | Delete Lines ESC[nM Deletes n lines including cursor line.
ICH | Insert Characters ESC[n@ Inserts n blank chars at cursor.
DCH | Delete Characters ESC[nP Deletes n chars including cursor char.
Mode-Setting
SGR Set Graphics Rendition ESC[n;n;...nm See character attribute table.
SM Set Mode ESC[=nh See screen mode table.
RM Reset Mode ESC[=nl See screen mode table.
IBMKKR Keyboard Key Reass. ESC["string"p
The first char of the string gives the key to redefine; the rest
of the string is the key's new value.
To specify unprintable chars, give the ASCII value of the char
outside of quotes, as a normal parameter.
IBM function keys are two byte strings; see the IBM Basic manual.
For instance, ESC[0;";dir a:";13;p redefines function key 1 to
have the value "dir a:" followed by the ENTER key.
| If no parameters given, all keys are reset to their default values.
DKOCT | Output char translate ESC[n;ny
| When first char is encountered in output request, it is replaced with
| the second char. This might be useful for previewing text before
| sending it to a printer with a funny print wheel.
| If no parameters are given, all chars are reset to normal.
Character Attributes
The Set Graphics Rendition command is used to select foreground
and background colors or attributes.
When you use multiple parameters, they are executed in sequence, and
the effects are cumulative.
Attrib code Value
0 All attributes off (normal white on black)
1 Bold
4 Underline
5 Blink
7 Reverse Video
8 Invisible (but why?)
30-37 foregnd blk/red/grn/yel/blu/magenta/cyan/white
40-47 background
Screen Modes
The IBM BIOS supports several video modes; the codes given in the
BIOS documentation are used as parameters to the Set Mode command.
| (In bitmap modes, the cursor is simulated with a small blob (^V).)
Mode Code Value
0 text 40x25 Black & White
1 text 40x25 Color
2 text 80x25 Black & White
3 text 80x25 Color
4 bitmap 320x200 4 bits/pixel
5 bitmap 320x200 1 bit/pixel
6 bitmap 640x200 1 bit/pixel
7 (cursor wrap kludge)
13 (EGA) bitmap 320x200 4 bits/pixel ?
14 (EGA) bitmap 640x200 4 bits/pixel
16 (EGA) bitmap 640x350 4 bits/pixel
Mode 7 is an unfortunate kludge; Setting mode 7 tells the cursor
to wrap around to the next line when it passes the end of a line;
Resetting mode 7 tells the cursor to not wrap, but rather stay put.
| If your computer has the Enhanced Graphics Adaptor, modes between
| 8 and 15 are also supported; see the EGA BIOS for info.
| The EGA also lets you use a shorter character cell in text modes
| in order to squeeze 43 lines of text out of the 25-line text modes.
| To enter 43 line mode, set the desired 25-line text mode (0 to 3),
| then Set Mode 43. For instance: ESC[=3h ESC[=43h.
| To exit 43 line mode, set the desired 25-line text mode again.
| Nansi.sys ignores mode 43 unless there is an EGA on your computer.
Faster Output
| Any program that sets the console to RAW mode, and buffers its
| output properly, can achieve extremely high screen update speeds in
| return for giving up the special functions of the keys ^C, ^S, and ^P.
| See IOCTL in the MS-DOS 3.x Technical Reference for more info.
Also, a small improvement in speed may be noticed with some
programs that use the DOS console in normal mode, as this driver
efficiently implements the (standard but undocumented) INT 29h
most-favored-device putchar used by DOS.
EXAMPLES
See the file setraw.doc for Macro Assembler, Lattice C,
and Microsoft C routines for entering and leaving raw mode.
BUGS
Insert and delete character do not work in graphics modes.
Graphics mode writing is slow.
The simulated cursor in graphics mode slows down single-char
writes by a factor of 3; it should be disable-able.
Does not support erase-to-end-of-screen and other useful functions.
Version
This version, 2.2, created February 1986. Problems should
be reported to Daniel Kegel, 1-60 CIT, Pasadena, CA 91126
(or, after June 1986, 2648 169th Ave SE, Bellevue, Wa. 98008).
Your suggestions for improvement would be most welcome.
NOTE
This program may be distributed for educational and personal use
only. Commercial use is verboten; get in touch with the author.
FILES
nansi.doc - this file
nansi.hex - compiled version <Not supported by INFO-IBMPC>
Convert nansi.hex into nansi.sys with the following commands
(you'll end up with 256 extra bytes at end, but who cares?):
debug # Run DOS debugger
N nansi.hex # Load the hex file
L
N nansi.sys # Write it out
W
Q # Quit- back to DOS.
nansi.cat - concatenated sources
nansi - makefile- shows how to assemble & link
nansi.asm - device driver guts
nansi_d.asm - definitions
nansi_p.asm - ANSI parameter grabber
nansi_f.asm - ANSI function handlers
nansi_i.asm - device driver init routine
setraw.cat - concatenated examples
setraw.asm - for assembly programs
setraw.msc - for Microsoft C programs
setraw.lc - for Lattice C programs
rawtest.lc - example for Lattice C only
--
Name: David P. Zimmerman Nickname: "Davidann" (don't ask)
Cute quote: " (well, *I* think it's cute!)
Arpa: dzimmerman at blue.rutgers.edu
Uucp: ...{harvard, allegra, seismo}!topaz!dpz
SHAR_EOF
echo shar: 1 control character may be missing from "'nansi.doc'"
if test 8584 -ne "`wc -c < 'nansi.doc'`"
then
echo shar: error transmitting "'nansi.doc'" '(should have been 8584 characters)'
fi
fi # end of overwriting check
if test -f 'nansi.asm'
then
echo shar: will not over-write existing file "'nansi.asm'"
else
cat << \SHAR_EOF > 'nansi.asm'
;--- nansi.asm ----------------------------------------------------------
; New ANSI terminal driver.
; Optimized for speed in the case of multi-character write requests.
; (C) 1986 Daniel Kegel, Pasadena, CA
; May be distributed for educational and personal use only
; The following files make up the driver:
; nansi.asm - all DOS function handlers except init
; nansi_p.asm - parameter parser for ANSI escape sequences
; nansi_f.asm - ANSI command handlers
; nansi_i.asm - init DOS function handler
;
; Daniel Kegel, Bellevue, Washington & Pasadena, California
; Revision history:
; 5 july 85: brought up non-ANSI portion except forgot backspace
; 6 july 85: split off ANSI stuff into other files, added backspace
; 11 july 85: fixed horrible bug in getchar; changed dosfns to subroutines
; 12 july 85: fixed some scrolling bugs, began adding compaq flag
; 9 aug 85: added cursor position reporting
; 10 aug 85: added output character translation
; 11 aug 85: added keyboard redefinition, some EGA 80x43 support
; 10 sept 85: Tandy 2000 support via compaq flag (finding refresh buffer)
; 30 Jan 86: removed Tandy 2000 stuff, added graphics mode support
; 12 feb 86: added int 29h handler, added PUSHA/POPA, added direct beep,
; direct cursor positioning, takeover of BIOS write_tty,
; noticed & squashed 2 related bugs in tab expansion
; 13 feb 86: Squashed them again, harder
; 24 feb 86: There is a bug in the timing code used by the BEEP routine.
; If the addition of the beep period to the
; BIOS low timer word results in an overflow, the beep will be
; supressed. Also made code compatible eith earlier versions
; of assembler.
;------------------------------------------------------------------------
include nansi_d.asm ; definitions
; from nansi_f.asm
extrn f_escape:near, f_in_escape:near
; from nansi_p.asm
extrn param_end:word, redef_end:word
; from nansi_i.asm
extrn dosfn0:near
; to nansi_p.asm
public f_loopdone
public f_not_ansi
public f_ansi_exit
; to both nansi_p.asm and nansi_f.asm
public cur_x, cur_y, max_x, cur_attrib
; to nansi_f.asm
public xy_to_regs, get_blank_attrib
public port_6845
public wrap_flag
public cur_parm_ptr
public cur_coords, saved_coords, max_y
public escvector, string_term
public cpr_esc, cprseq
public video_mode
public lookup
public in_g_mode
; to nansi_i.asm
public req_ptr, break_handler
public int_29
if takeBIOS
public new_vid_bios, old_vid_bios
endif
; to all modules
public xlate_tab_ptr
;--- seg_cs is the CS: override prefix
; (assembler forgets cs: on second "xlat dummy_cs_byte")
seg_cs macro
db 2eh
endm
;--- push_all, pop_all ------------------------------------------------
; Save/restore all user registers.
push_all macro
if is_8088
push ax
push bx
push cx
push dx
push bp
push si
push di
else
pusha
endif
endm
pop_all macro
if is_8088
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
else
popa
endif
endm
keybuf struc ; Used in getchar
len dw ?
adr dw ?
keybuf ends
ABS40 segment at 40h
org 1ah
buffer_head dw ? ; Used in 'flush input buffer' dos call.
buffer_tail dw ?
org 49h
crt_mode db ?
crt_cols dw ?
crt_len dw ?
crt_start dw ?
cursor_posn dw 8 dup (?)
cursor_mode dw ?
active_page db ?
addr_6845 dw ?
crt_mode_set db ? ; = 7 only if monochrome display adaptor
crt_palette db ?
org 6ch
timer_low dw ? ; low word of time-of-day counter (18.2 hz)
ABS40 ends
page
CODE segment byte public 'CODE'
assume cs:code, ds:code
; Device Driver Header
org 0
dd -1 ; next device
dw 8013h ; attributes
dw strategy ; request header pointer entry
dw interrupt ; request entry point
db 'CON' ; device name (8 char)
db 5 dup (20h) ; ... and 5 blanks)
; Identification- in case somebody TYPEs the assembled driver
db 27,'[2J'
db "Nansi.sys v2.2"
ife is_8088
db "(80286)"
endif
db ': New ANSI driver (C) Daniel Kegel, Pasadena, CA 1986'
db 13, 10, 26
;----- variable area --------------------
req_ptr label dword
req_off dw ?
req_seg dw ?
wrap_flag db 1 ; 0 = no wrap past line end
escvector dw 0 ; state vector of ESCape sequencor
video_mode db 3 ; ROM BIOS video mode (2=BW, 3=color)
max_y db 24
max_cur_x label word ; used to get both max & cur at once
max_x db 79 ; line width (79 for 80x25 modes)
cur_coords label word
cur_x db 0 ; cursor position (0 = left edge)
cur_y db 0 ; (0 = top edge)
saved_coords dw ? ; holds XY after a SCP escape sequence
string_term db 0 ; either escape or double quote
cur_attrib db 7 ; current char attributes
cur_page db 0 ; current display page
video_seg dw ? ; segment of video card
f_cptr_seg dw ? ; part of fastout write buffer pointer
cur_parm_ptr dw ? ; last byte of parm area now used
port_6845 dw ? ; port address of 6845 card
xlate_tab_ptr dw ? ; pointer to output translation table
if takeBIOS
old_vid_bios dd ? ; pointer to old video bios routine
endif
brkkeybuf db 3 ; control C
fnkeybuf db ? ; holds second byte of fn key codes
cpr_buf db 8 dup (?), '['
cpr_esc db 1bh ; descending buffer for cpr function
; following four keybufs hold information about input
; Storage order determines priority- since the characters making up a function
; key code must never be separated (say, by a Control-Break), they have the
; highest priority, and so on. Keyboard keys (except ctrl-break) have the
; lowest priority.
fnkey keybuf <0, fnkeybuf> ; fn key string (0 followed by scan code)
cprseq keybuf <0> ; CPR string (ESC [ y;x R)
brkkey keybuf <0, brkkeybuf> ; ^C
xlatseq keybuf <0> ; keyboard reassignment string
;------ xy_to_regs --------------------------------------------
; on entry: x in cur_x, y in cur_y
; on exit: dx = chars left on line, di = address
; Alters ax, bx.
xy_to_regs proc near
; Find number of chars 'till end of line, keep in DX
mov ax, max_cur_x
mov bx, ax ; save max_x & cur_x for next block
mov ah, 0 ; ax = max_x
xchg dx, ax
mov al, bh
mov ah, 0 ; ax = cur_x
sub dx, ax
inc dx ; dx is # of chars till EOL
; Calculate DI = current address in text buffer
mov al, bl ; al = max_x
inc al
mul cur_y
add al, bh ; al += cur_x
adc ah, 0 ; AX is # of chars into buffer
add ax, ax
xchg di, ax ; DI is now offset of cursor.
ret
xy_to_regs endp
;------- dos_fn_tab -------------
; This table is used in "interrupt" to call the routine that handles
; the requested function.
max_cmd equ 12
dos_fn_tab:
dw dosfn0, nopcmd, nopcmd, badcmd, dosfn4, dosfn5, dosfn6
dw dosfn7, dosfn8, dosfn8, nopcmd, nopcmd
;------- strategy ----------------------------------------------------
; DOS calls strategy with a request which is to be executed later.
; Strategy just saves the request.
strategy proc far
mov cs:req_off,BX
mov cs:req_seg,ES
ret
strategy endp
;------ interrupt -----------------------------------------------------
; This is where the request handed us during "strategy" is
; actually carried out.
; Calls one of 12 subroutines depending on the function requested.
; Each subroutine returns with exit status in AX.
interrupt proc far
sti
push_all ; preserve caller's registers
push ds
push es
; Read requested function information into registers
lds bx,cs:req_ptr
mov al,[BX+02h] ; al = function code
;
; The next instruction blows up MASM 1.0 but who cares!!
;
les si,[BX+0Eh] ; ES:SI = input/output buffer addr
mov cx,[BX+12h] ; cx = input/output byte count
cmp al, max_cmd
ja unk_command ; too big, exit with error code
xchg bx, ax
shl bx, 1 ; form index to table of words
mov ax, cs
mov ds, ax
call word ptr dos_fn_tab[bx]
int_done:
lds bx,cs:req_ptr ; report status
or ax, 100h ; (always set done bit upon exit)
mov [bx+03],ax
pop ES ; restore caller's registers
pop DS
pop_all
ret ; return to DOS.
unk_command:
call badcmd
jmp int_done
interrupt endp
;----- BIOS break handler -----------------------------------------
; Called by BIOS when Control-Break is hit (vector was set up in Init).
; Simply notes that a break was hit. Flag is checked during input calls.
break_handler proc
mov cs:brkkey.len, 1
iret
break_handler endp
page
;------ badcmd -------------------------------------------------------
; Invalid function request by DOS.
badcmd proc near
mov ax, 813h ; return "Error: invalid cmd"
ret
badcmd endp
;------ nopcmd -------------------------------------------------------
; Unimplemented or dummy function request by DOS.
nopcmd proc near
xor ax, ax ; No error, not busy.
ret
nopcmd endp
;------- dos function #4 ----------------------------------------
; Reads CX characters from the keyboard, places them in buffer at
; ES:SI.
dosfn4 proc near
jcxz dos4done
mov di, si
dos4lp: push cx
call getchar
pop cx
stosb
loop dos4lp
dos4done:
xor ax, ax ; No error, not busy.
ret
dosfn4 endp
;-------- dos function #5: non-destructive input, no wait ------
; One-character lookahead into the keyboard buffer.
; If no characters in buffer, return BUSY; otherwise, get value of first
; character of buffer, stuff into request header, return DONE.
dosfn5 proc near
call peekchar
jz dos5_busy
lds bx,req_ptr
mov [bx+0Dh], al
xor ax, ax ; No error, not busy.
jmp short dos5_exit
dos5_busy:
MOV ax, 200h ; No error, busy.
dos5_exit:
ret
dosfn5 endp
;-------- dos function #6: input status --------------------------
; Returns "busy" if no characters waiting to be read.
dosfn6 proc near
call peekchar
mov ax, 200h ; No error, busy.
jz dos6_exit
xor ax, ax ; No error, not busy.
dos6_exit:
ret
dosfn6 endp
;-------- dos function #7: flush input buffer --------------------
; Clears the IBM keyboard input buffer. Since it is a circular
; queue, we can do this without knowing the beginning and end
; of the buffer; all we need to do is set the tail of the queue
; equal to the head (as if we had read the entire queue contents).
; Also resets all the device driver's stuffahead buffers.
dosfn7 proc near
xor ax, ax
mov fnkey.len, ax ; Reset the stuffahead buffers.
mov cprseq.len, ax
mov brkkey.len, ax
mov xlatseq.len, ax
mov ax, abs40
mov es, ax
mov ax, es:buffer_head ; clear queue by making the tail
mov es:buffer_tail, ax ; equal to the head
xor ax, ax ; no error, not busy.
ret
dosfn7 endp
page
if takeBIOS
;--- new_vid_bios -------------------------------------------
; New_vid_bios simply replaces the write_tty call.
; All other calls get sent to the old video bios.
; This gives BIOS ANSI capability.
; However, it takes away the escape character.
; If this is not desired, just tell init to not take over the vector.
new_vid_bios proc
cmp ah, 14
jz nvb_write_tty
jmp dword ptr cs:old_vid_bios
nvb_write_tty:
push cx
mov cl, cs:cur_attrib
; If in graphics mode, BL is new color
call in_g_mode ; returns carry set if text mode
jc nvb_wt_text
mov cs:cur_attrib, bl ; ja?
nvb_wt_text:
int 29h ; write AL
mov cs:cur_attrib, cl ; restore color
pop cx
iret
new_vid_bios endp
endif
;------ int_29 ----------------------------------------------
; Int 29 handles DOS quick-access putchar.
; Last device loaded with attribute bit 4 set gets accessed for
; single-character writes via int 29h instead of via interrupt.
; Must preserve all registers.
; Installed as int 29h by dosfn0 (init).
int_29_buf db ?
int_29 proc near
sti
push ds
push es
push_all
mov cx, 1
mov bx, cs
mov es, bx
mov ds, bx
mov si, offset int_29_buf
mov byte ptr [si], al
call dosfn8
pop_all
pop es
pop ds
iret
int_29 endp
page
;------ dosfn8 -------------------------------------------------------
; Handles writes to the device (with or without verify).
; Called with
; CX = number of bytes to write
; ES:SI = transfer buffer
; DS = CS, so we can access local variables.
dosfn8 proc near
mov f_cptr_seg, es ; save segment of char ptr
; Read the BIOS buffer address/cursor position variables.
mov ax, abs40
mov ds, ax
assume ds:abs40
; Find current video mode and screen size.
mov ax,word ptr crt_mode ; al = crt mode; ah = # of columns
mov cs:video_mode, al
dec ah ; ah = max column
mov cs:max_x, ah
; Find current cursor coordinates.
mov al,active_page
cbw
add ax,ax
xchg bx,ax
mov ax,cursor_posn[bx]
mov cs:cur_coords,AX
; Find video buffer segment address; adjust it
; so the offset is zero; return in AX.
; DS is abs40.
; Find 6845 address.
mov ax, addr_6845
mov cs:port_6845, ax
; Find video buffer address.
MOV AX,crt_start
shr ax, 1
shr ax, 1
shr ax, 1
shr ax, 1
add ah, 0B0h ; assume it's a monochrome card...
CMP cs:video_mode,07
jz d8_gots
add ah, 8 ; but if not mode 7, it's color.
d8_gots:
push cs
pop ds
assume ds:code
mov video_seg, ax
mov es, ax
call xy_to_regs ; Set DX, DI according to cur_coords.
; | If in graphics mode, clear old pseudocursor
call in_g_mode
jc d8_no_cp
call pseudocursor ; write block in xor
d8_no_cp:
mov bx, xlate_tab_ptr ; get pointer to translation table
mov ah, cur_attrib
mov ds, f_cptr_seg ; get segment of char ptr
assume ds:nothing
cld ; make sure we'll increment
; The Inner Loop: 4+12 +4+4 +4+4 +0+15 +4+4 +4+18 = 77 cycles/loop
; on 8088; at 4.77 MHz, that gives 16.1 microseconds/loop.
; At that speed, it takes 32 milliseconds to fill a screen.
; Get a character, put it on the screen, repeat 'til end of line
; or no more characters.
jcxz f_loopdone ; if count = 0, we're already done.
cmp cs:escvector, 0 ; If in middle of an escape sequence,
jnz f_in_escapex ; jump to escape sequence handler.
f_tloop:; | If in graphics mode, jump to alternate loop
; | What a massive kludge! A better approach would have been
; | to collect characters for a "write n chars" routine
; | which would handle both text and graphics modes.
call in_g_mode
jc f_t_cloop
jmp f_g_cloop
f_t_cloop:
LODSB ; get char! (al = ds:[si++])
cmp al, 28 ; is it a control char?
jb f_control ; maybe...
f_t_nctl:
seg_cs
xlat
STOSW ; Put Char! (es:[di++] = ax)
dec dx ; count down to end of line
loopnz f_t_cloop ; and go back for more.
jz f_t_at_eol ; at end of line; maybe do a crlf.
jmp short f_loopdone
f_looploop:
f_ansi_exit: ; in case we switched into
loopnz f_tloop ; a graphics mode
f_t_at_eol:
jz f_at_eol
f_loopdone:
;--------- All done with write request -----------
; DI is cursor address; cursor position in cur_y, dl.
mov ax, cs
mov ds, ax ; get our segment back
assume ds:code
; Restore cur_x = max_x - dx + 1.
mov al, max_x
inc al
sub al, dl
mov cur_x, al
; Set cursor position; cursor adr in DI; cursor pos in cur_x,cur_y
call set_pseudocursor
; Return to DOS.
xor ax, ax ; No error, not busy.
ret
;---- handle control characters ----
; Note: cur_x is not kept updated in memory, but can be
; computed from max_x and dx.
; Cur_y is kept updated in memory.
f_control:
cmp al, 27 ; Is it an escape?
jz f_escapex
cmp al, 13 ; carriage return?
jz f_cr
cmp al, 10 ; line feed?
jz f_lf
cmp al, 9 ; tab?
jz f_tabx
cmp al, 8 ; backspace?
jz f_bs
cmp al, 7 ; bell?
jz f_bell
jmp f_nctl ; then it is not a control char.
f_tabx: jmp f_tab
f_escapex:
jmp f_escape
f_in_escapex:
jmp f_in_escape
f_bs: ;----- Handle backspace -----------------
; Moves cursor back one space without erasing. No wraparound.
cmp dl, cs:max_x ; wrap around to previous line?
ja fbs_wrap ; yep; disallow it.
dec di ; back up one char & attrib,
dec di
inc dx ; and note one more char left on line.
fbs_wrap:
jmp f_looploop
f_bell: ;----- Handle bell ----------------------
; Use BIOS to do the beep. DX is not changed, as bell is nonprinting.
call beep
or al, al ; clear z
; old (more portable) version:
; mov ax, 0e07h ; "write bell to tty simulator"
; mov bx, 0 ; "page zero, color black"
; int 10h ; call BIOS
; mov ah, cs:cur_attrib ; restore current attribute
; mov bx, cs:xlate_tab_ptr ; restore translate table address
; or al, al ; al still 7; this clears Z.
jmp f_looploop ; Let main loop decrement cx.
f_cr: ;----- Handle carriage return -----------
; di -= cur_x<<1; set di= address of start of line
; dx=max_x+1; set bx= chars left in line
mov al, cs:max_x
inc al
sub al, dl ; Get cur_x into ax.
mov ah, 0
sub di, ax
sub di, ax
mov dl, cs:max_x ; Full line ahead of us.
inc dx
mov ah, cs:cur_attrib ; restore current attribute
or al, 1 ; clear z
jmp f_looploop ; and let main loop decrement cx
f_at_eol:
;----- Handle overrunning right end of screen -------
; cx++; compensate for double loop
; if (!wrap_flag) { dx++; di-=2; }
; else do_crlf;
inc cx
test cs:wrap_flag, 1
jnz feol_wrap
dec di
dec di
inc dx
jmp f_looploop
feol_wrap:
; dx=max_x+1; set bx= chars left in line
; di -= 2*(max_x+1);
; do_lf
mov dl, cs:max_x
inc dx
sub di, dx
sub di, dx
; fall thru to line feed routine
f_lf: ;----- Handle line feed -----------------
; if (cur_y >= max_y) scroll; scroll screen up if needed
; else { cur_y++; di += max_x<<1; else increment Y
mov al, cs:max_y
cmp cs:cur_y, al
jb flf_noscroll
call scroll_up ; preserves bx,cx,dx,si,di
jmp short flf_done
flf_noscroll:
inc cs:cur_y
mov al, cs:max_x
mov ah, 0
inc ax
add ax, ax
add di, ax
flf_done:
mov ah, cs:cur_attrib ; restore current attribute
or al, 1 ; clear z
jmp f_looploop ; and let main loop decrement cx
f_tab: ;----- Handle tab expansion -------------
; Get cur_x into al.
mov al, cs:max_x
inc al
sub al, dl
; Calculate number of spaces to output.
push cx ; save cx
mov ch, 0
mov cl, al ; get zero based x coordinate
and cl, 7
neg cl
add cl, 8 ; 0 -> 8, 1 -> 8, ... 7 -> 1
sub dx, cx ; update chars-to-eol, maybe set z
pushf ; || save Z for main loop
; ah is still current attribute. Move CX spaces to the screen.
mov al, ' '
call in_g_mode ; | graphics mode
jnc f_tab_putc ; |
REP STOSW
popf ; || restore Z flag for main loop test
pop cx ; restore cx
jmp f_looploop ; Let main loop decrement cx.
;--------------- graphics mode support -----------------------
f_tab_putc: ; graphics mode- call putc to put the char
add dx, cx ; move back to start of tab
f_tp_lp:
call putchar
dec dx ; go to next cursor position
loop f_tp_lp
popf ; Z set if wrapped around EOL
pop cx
jmp f_looploop
;---- in_g_mode -------------
; Returns Carry set if not in a graphics mode.
; Preserves all registers.
in_g_mode proc near
cmp cs:video_mode, 4
jb igm_stc
cmp cs:video_mode, 7
jz igm_stc
clc
ret
igm_stc:
stc
ret
in_g_mode endp
;---- Where to go when a character turns out not to be special
f_nctl:
f_not_ansi:
call in_g_mode
jnc f_g_nctl ; graphics mode
f_jmptnctl:
jmp f_t_nctl ; text mode
;---- Alternate main loop for graphics mode ----
f_g_cloop:
LODSB ; get char! (al = ds:[si++])
cmp al, 28 ; is it a control char?
jb f_g_control ; maybe...
f_g_nctl:
seg_cs
xlat
call putchar
dec dx ; count down to end of line
loopnz f_g_cloop ; and go back for more.
jz f_g_at_eol ; at end of line; maybe do a crlf.
jmp f_loopdone
f_g_control: jmp f_control
f_g_at_eol: jmp f_at_eol
;---- putchar ------------------------------------------------
; Writes char AL, attribute AH to screen at (max_x+1-dl), cur_y.
; On entry, registers set up as per xy_to_regs.
; Preserves all registers.
putchar proc near
push dx
push cx
push bx
push ax
; 1. Set cursor position.
mov al, cs:max_x
inc al
sub al, dl
mov cs:cur_x, al
mov dx, cs:cur_coords ; get X & Y into DX
xor bx, bx ; choose dpy page 0
mov ah, 2 ; chose "Set Cursor Position"
int 10h ; call ROM BIOS
; 2. Write char & attribute.
mov cx, 1
pop ax ; get char in AL
push ax
mov bl, ah ; attribute in BL
mov bh, 0
mov ah, 9
int 10h
pop ax
pop bx
pop cx
pop dx
ret
putchar endp
;---- set_pseudocursor ------------
; If in graphics mode, set pseudocursor, else set real cursor.
; Destroys DS!!!!
set_pseudocursor proc near
call in_g_mode
jnc pseudocursor
; old (more portable, but slower) version
; mov dx, cur_coords ; get X & Y into DX
; xor bx, bx ; choose dpy page 0
; mov ah, 2 ; chose "Set Cursor Position"
; int 10h ; call ROM BIOS
; Write directly to 6845 cursor address register.
mov bx, di
shr bx, 1 ; convert word index to byte index
mov dx, port_6845
mov al, 0eh
out dx, al
jmp $+2
inc dx
mov al, bh
out dx, al
jmp $+2
dec dx
mov al, 0fh
out dx, al
jmp $+2
inc dx
mov al, bl
out dx, al
; Set cursor position in low memory.
assume ds:abs40
mov ax, abs40
mov ds, ax
; Does anybody ever use anything but page zero?
; mov al,active_page
; cbw
; add ax,ax
; xchg bx,ax
mov ax, cs:cur_coords
mov cursor_posn,ax
ret
assume ds:code
set_pseudocursor endp
;---- pseudocursor --------------------------------------------------
; Writes a color 15 block in XOR at the current cursor location.
; Preserves DS, ES, BX, CX, DX, SI, DI.
; Should be disableable- the pseudocursor slows down single-char
; writes by a factor of three.
pseudocursor proc near
mov ax, 8f16h ; xor, color 15, ^V (small block)
call putchar
ret
pseudocursor endp
;--------------- end of graphics mode support --------------------
dosfn8 endp
;--- get_blank_attrib ------------------------------------------------
; Determine new attribute and character for a new blank region.
; Use current attribute, just disallow blink and underline.
; (Pretty strange way to do it. Might want to disallow rev vid, too.)
; Returns result in AH, preserves all other registers.
get_blank_attrib proc near
mov ah, 0
call in_g_mode
jnc gb_aok ; if graphics mode, 0 is bkgnd
mov ah, cs:cur_attrib
and ah, 7fh ; disallow blink
cmp cs:video_mode, 7 ; monochrome?
jnz gb_aok
cmp ah, 1 ; underline?
jnz gb_aok
mov ah, 7 ; yep- set it to normal.
gb_aok: ret
get_blank_attrib endp
;---- scroll_up ---------------------------------------------------
; Scroll screen up- preserves ax, bx, cx, dx, si, di, ds, es.
; Moves screen up 1 line, fills the last line with blanks.
; Attribute of blanks is the current attribute sans blink and underline.
scroll_up proc near
push ax
push bx
push cx
push dx
call get_blank_attrib
mov bh, ah ; color to use on new blank areas
mov al, 1 ; AL is number of lines to scroll.
mov ah, 6 ; BIOS: scroll up
mov cl, 0 ; upper-left-x of data to scroll
mov ch, 0 ; upper-left-y of data to scroll
mov dl, cs:max_x ; lower-rite-x
mov dh, cs:max_y ; lower-rite-y (zero based)
int 10h ; call BIOS to scroll a rectangle.
pop dx
pop cx
pop bx
pop ax
ret
scroll_up endp
;---- lookup -----------------------------------------------
; Called by getchar, peekchar, and key to see if a given key has
; been redefined.
; Sets AH to zero if AL is not zero (i.e. if AX is not a function key).
; Returns with Z cleared if no redefinition; otherwise,
; Z is set, SI points to redefinition string, CX is its length.
; Preseves AL, all but CX and SI.
; Redefinition table organization:
; Strings are stored in reversed order, first char last.
; The word following the string is the character to be replaced;
; the next word is the length of the string sans header.
; param_end points to the last byte used by the parameter buffer;
; redef_end points to the last word used by the redef table.
lookup proc near
mov si, redef_end ; Start at end of table, move down.
or al, al
jz lu_lp
mov ah, 0 ; clear extraneous scan code
lu_lp: cmp si, param_end
jbe lu_notfound ; If below redef table, exit.
mov cx, [si]
cmp ax, [si-2] ; are you my mommy?
jz lu_gotit
sub si, 4
sub si, cx ; point to next header
jmp lu_lp
lu_notfound:
or si, si ; clear Z
jmp short lu_exit
lu_gotit:
sub si, 2
sub si, cx ; point to lowest char in memory
cmp al, al ; set Z
lu_exit:
ret
lookup endp
;---- searchbuf --------------------------------------------
; Called by getchar and peekchar to see if any characters are
; waiting to be gotten from sources other than BIOS.
; Returns with Z set if no chars found, BX=keybuf & SI=keybuf.len otherwise.
searchbuf proc near
; Search the stuffahead buffers.
mov cx, 4 ; number of buffers to check for chars
mov bx, offset fnkey - 4
sbloop: add bx, 4 ; point to next buffer record
mov si, [bx].len
or si, si ; empty?
loopz sbloop ; if so, loop.
ret
searchbuf endp
;---- getchar -----------------------------------------------
; Returns AL = next char.
; Trashes AX, BX, CX, BP, SI.
getchar proc near
gc_searchbuf:
; See if any chars are waiting in stuffahead buffers.
call searchbuf
jz gc_trykbd ; No chars? Try the keyboard.
; A nonempty buffer was found.
dec [bx].len
dec si
mov bp, [bx].adr ; get pointer to string
mov al, byte ptr ds:[bp][si]; get the char
; Recognize function key sequences, move them to highest priority
; queue.
sub si, 1 ; set carry if si=0
jc gc_nofnkey ; no chars left -> nothing to protect.
cmp bx, offset fnkey
jz gc_nofnkey ; already highest priority -> done.
or al, al
jnz gc_nofnkey ; nonzero first byte -> not fnkey.
; Found a function key; move it to highest priority queue.
dec [bx].len
mov ah, byte ptr ds:[bp][si]; get the second byte of fn key code
gc_fnkey:
mov fnkey.len, 1
mov fnkeybuf, ah ; save it.
gc_nofnkey:
; Valid char in AL. Return with it.
jmp short gcdone
gc_trykbd:
; Actually get a character from the keyboard.
mov ah, 0
int 16h ; BIOS returns with char in AX
; If it's Ctrl-break, it has already been taken care of.
or ax, ax
jz gc_trykbd
; Look in the reassignment table to see if it needs translation.
call lookup ; Z=found; CX=length; SI=ptr
jnz gc_noredef
; Okay; set up the reassignment, and run thru the translation code.
mov xlatseq.len, cx
mov xlatseq.adr, si
jmp gc_searchbuf
gc_noredef:
; Is it a function key?
cmp al, 0
jz gc_fnkey ; yep- special treatment.
gcdone: ret ; with character in AL.
getchar endp
;---- peekchar -----------------------------------------------
; Returns Z if no character ready, AL=char otherwise.
; Trashes AX, BX, CX, BP, SI.
peekchar proc near
pc_searchbuf:
call searchbuf
jz pc_trykbd ; No chars? Try the keyboard.
; A nonempty buffer was found.
dec si
mov bp, [bx].adr ; get pointer to string
mov al, byte ptr ds:[bp][si]; get the char
; Valid char from buffer in AL. Return with it.
jmp short pcdone
pc_trykbd:
; Actually peek at the keyboard.
mov ah, 1
int 16h ; BIOS returns with char in AX
jz pcexit
; If it's control-break, it's already been taken care of.
or ax, ax
jnz pc_notbrk
mov ah, 0
int 16h ; so get rid of it!
jmp short pc_trykbd
pc_notbrk:
; Look in the reassignment table to see if it needs translation.
call lookup ; Z=found; CX=length; SI=ptr
jnz pcdone ; Nope; just return the char.
; Okay; get the first code to be returned.
add si, cx
mov al, [si-1]
pcdone: or ah, 1 ; NZ; char ready!
pcexit: ret ; with character in AL, Z true if no char waiting.
peekchar endp
;---- beep ------------------------------------------------------
; Beep speaker; period given by beep_div, duration by beep_len.
; Preserves all registers.
beep_div dw 1300 ; fairly close to IBM beep
beep_len dw 3 ; 3/18 sec- shorter than IBM
beep proc near
push_all
mov al, 10110110b ; select 8253
mov dx, 43h ; control port address
out dx, al
dec dx ; timer 2 address
mov ax, cs:beep_div
jmp $+2
out dx, al ; low byte of divisor
xchg ah, al
jmp $+2
out dx, al ; high byte of divisor
mov dx, 61h
jmp $+2
in al, dx ; get current value of control bits
push ax
or al, 3
jmp $+2
out dx, al ; turn speaker on
; Wait for desired duration by monitoring time-of-day 18 Hz clock
push es
mov ax, abs40
mov es, ax
assume es:abs40
mov bx, timer_low
mov cx, -1
beeplp: mov ax, timer_low
sub ax, bx
cmp ax, cs:beep_len
jg beepover
loop beeplp
beepover:
pop es
assume es:code
; Turn off speaker
pop ax
and al, not 3 ; turn speaker off
out dx, al
pop_all
ret
beep endp
CODE ends
end ; of nansi.asm
page 66, 132
SHAR_EOF
if test 27957 -ne "`wc -c < 'nansi.asm'`"
then
echo shar: error transmitting "'nansi.asm'" '(should have been 27957 characters)'
fi
fi # end of overwriting check
if test -f 'nansi_d.asm'
then
echo shar: will not over-write existing file "'nansi_d.asm'"
else
cat << \SHAR_EOF > 'nansi_d.asm'
;---- nansi_d.asm -----------------
; Definitions for the new ANSI driver.
; (C) 1986 Daniel Kegel
; May be distributed for educational and personal use only
takeBIOS equ 0 ; take over BIOS write_tty if true
is_8088 equ 1 ; no fancy instructions if true
cls_homes_too equ 1 ; set true for ANSI.SYS compatibility
;Comment this out if running MASM 1.0
if is_8088
.8086
else
.286c
endif
;---- end of nansi_d.asm ----
page 66, 132
;--- nansi.asm ----------------------------------------------------------
SHAR_EOF
if test 514 -ne "`wc -c < 'nansi_d.asm'`"
then
echo shar: error transmitting "'nansi_d.asm'" '(should have been 514 characters)'
fi
fi # end of overwriting check
if test -f 'nansi_f.asm'
then
echo shar: will not over-write existing file "'nansi_f.asm'"
else
cat << \SHAR_EOF > 'nansi_f.asm'
;----- nansi_f.asm ---------------------------------------------
; The ANSI control subroutines.
; (C) 1986 Daniel Kegel, Pasadena, CA
; May be distributed for educational and personal use only
; Each routine is called with the following register usage:
; AX = max(1, value of first parameter)
; Z flag is set if first parameter is zero.
; CX = number of paramters
; SI = offset of second parameter from CS
; DS = CS
; ES:DI points to the current location on the memory-mapped screen.
; DX is number of characters remaining on the current screen line.
; The control routine is free to trash AX, BX, CX, SI, and DS.
; It must preserve ES, and can alter DX and DI if it wants to move the
; cursor.
;
; Revisions:
; 19 Aug 85: Fixed horrible bug in insert/delete line.
; 26 Aug 85: Fixed simple limit-to-one-too-few-lines bug in ins/del line;
; anyway, it inserts 24 lines when on line 2 now. Whether it's fixed...
; 4 Sept 85: Fixed bug created on 26 Aug 85; when limiting ins/del line
; count, we are clearing, not scrolling; fixed BIOS call to reflect this.
; 30 Jan 86: Added EGA cursor patch
; 31 Jan 86: Disabled insert/delete char in graphics modes
; Implemented keyboard redefinition reset
; 1 Feb 86: added video_mode and max_x test after mode set
;----------------------------------------------------------------
include nansi_d.asm
; To nansi_p.asm
public ansi_fn_table
; From nansi.asm
extrn port_6845:word
extrn cur_coords:word, saved_coords:word
extrn cur_x:byte, max_x:byte
extrn cur_y:byte, max_y:byte
extrn cur_attrib:byte, wrap_flag:byte
extrn xy_to_regs:near
extrn get_blank_attrib:near
extrn xlate_tab_ptr:word
extrn cpr_esc:byte, cprseq:word
extrn video_mode:byte
extrn lookup:near
extrn in_g_mode:near
; from nansi_p.asm
extrn param_buffer:word ; used in keyboard programming
extrn param_end:word
extrn redef_end:word
keybuf struc ; used in making cpr sequence
len dw ?
adr dw ?
keybuf ends
ABS40 segment at 40h
org 1ah
buffer_head dw ? ; Used in 'flush input buffer' dos call.
buffer_tail dw ?
org 49h
crt_mode db ?
crt_cols dw ?
crt_len dw ?
crt_start dw ?
cursor_posn dw 8 dup (?)
cursor_mode dw ?
active_page db ?
addr_6845 dw ?
crt_mode_set db ?
crt_palette db ?
ABS40 ends
code segment byte public 'CODE'
assume cs:code, ds:code
;----- byteout ---------------------------------------------------
; Converts al to a decimal ASCII string (in 0..99),
; stores it at ES:DI++. Returns DI pointing at byte after last digit.
; Destroys DL.
byteout proc near
aam
add ax, 3030h
xchg ah, al
stosb
xchg ah, al
stosb
ret
byteout endp
;----- ansi_fn_table -----------------------------------
; Table of offsets of terminal control subroutines in order of
; the character that invokes them, @..Z, a..z. Exactly 53 entries.
; All the subroutines are defined below in this module.
ansi_fn_table label word
dw ic, cup, cdn, cfw, cbk ; @, A, B, C, D
dw nul, nul, nul, hvp, nul ; E, F, G, H, I
dw eid, eil, il, d_l, nul ; J, K, L, M, N
dw nul, dc, nul, nul, nul ; O, P, Q, R, S
dw nul, nul, nul, nul, nul ; T, U, V, W, X
dw nul, nul ; Y, Z
dw nul, nul, nul, nul, nul ; a, b, c, d, e
dw hvp, nul, sm, nul, nul ; f, g, h, i, j
dw nul, rm, sgr, dsr, nul ; k, l, m, n, o
dw key, nul, nul, scp, nul ; p, q, r, s, t
dw rcp, nul, nul, nul, xoc ; u, v, w, x, y
dw nul ; z
ansi_functions proc near ; set return type to NEAR
;----- nul ---------------------------------------------
; No-action ansi sequence; called when unknown command given.
nul: ret
;----- Cursor Motion -----------------------------------------------
;-- cursor to y,x
hvp: or al, al ; First parameter is desired Y coordinate.
jz hvp_yok
dec ax ; Convert to zero-based coordinates.
hvp_yok:mov cur_y, al
; Get second parameter, if it is there, and set X with it.
xor ax, ax
cmp cx, 2 ; was there a second parameter?
jb hvp_xok
lodsb ; yes.
or al, al
jz hvp_xok
dec ax ; convert to zero-based coordinates.
hvp_xok:mov cur_x, al
; Clip to maximum coordinates.
hvp_set:
mov ax, cur_coords ; al = x, ah = y
cmp al, max_x
jbe hvp_sxok
mov al, max_x
mov cur_x, al
hvp_sxok:
cmp ah, max_y
jbe hvp_syok
mov al, max_y
mov cur_y, al
hvp_syok:
; Set values of DX and DI accordingly.
call xy_to_regs
ret
;-- cursor forward --
cfw: add cur_x, al
jmp hvp_set
;-- cursor back -----
cbk: sub cur_x, al
jae cbk_ok
mov cur_x, 0
cbk_ok: jmp hvp_set
;-- cursor down -----
cdn: add cur_y, al
jmp hvp_set
;-- cursor up -------
cup: sub cur_y, al
jae cup_ok
mov cur_y, 0
cup_ok: jmp hvp_set
;-- save cursor position --------------------------------------
scp: mov ax, cur_coords
mov saved_coords, ax
ret
;-- restore cursor position -----------------------------------
rcp: mov ax, saved_coords
mov cur_coords, ax
jmp hvp_set ; Clip in case we have switched video modes.
;-- set graphics rendition ------------------------------------
; Modifies the color in which new characters are written.
sgr: dec si ; get back pointer to first parameter
or cx, cx ; Did he give any parameters?
jnz sgr_loop
mov byte ptr [si], 0 ; no parameters, so fake
inc cx ; one with the default value.
; For each parameter
sgr_loop:
lodsb ; al = next parameter
; Search color table
push cx
mov cx, colors
mov bx, offset color_table-3
sgr_search:
add bx, 3
cmp al, byte ptr [bx]
loopnz sgr_search ; until match found or done
jnz sgr_loopx
; If parameter named a known color, set the current
; color variable.
mov ax, [bx+1]
and cur_attrib, al
or cur_attrib, ah
sgr_loopx:
pop cx
loop sgr_loop ; until no more parameters.
ret
;-- erase in line ----------------------------------------
; Uses BIOS to scroll away a one-line rectangle
eil: push dx
mov cx, cur_coords
mov dh, ch
jmp short scrollem
;-- erase in display -------------------------------------
; Uses BIOS to scroll away all of display
eid: cmp al, 2
jnz eid_ignore ; param must be two
if cls_homes_too
mov cur_coords, 0
call xy_to_regs
endif
push dx
xor cx, cx
mov dh, max_y
scrollem:
call get_blank_attrib
mov bh, ah
mov dl, max_x
mov ax, 600h
int 10h
pop dx
eid_ignore:
ret
;-- device status report --------------------------------
; Stuffs an escape, a left bracket, current Y, semicolon, current X,
; a capital R, and a carriage return into input stream.
; The coordinates are 1 to 3 decimal digits each.
dsr: push di
push dx
push es
mov ax, cs
mov es, ax
std ; Store string in reversed order for fun
mov di, offset cpr_esc - 2
mov al, cur_y
inc al ; convert to one-based coords
call byteout ; row
mov al, ';' ; ;
stosb
mov al, cur_x
inc al ; convert to one-based coords
call byteout ; column
mov al, 'R' ; R ANSI function 'Cursor Position Report'
stosb
mov al, 13
mov word ptr cprseq.adr, di ; save pointer to last char in string
stosb ; send a carriage return, too
mov ax, offset cpr_esc
sub ax, di ; ax is # of characters in string
mov word ptr cprseq.len, ax ; pass info to the getchar routine
cld
pop es
pop dx
pop di
ret
;-- keyboard reassignment -------------------------------
; Key reassignment buffer is between param_end and redef_end+2, exclusive.
; When it shrinks or grows, param_end is moved.
; Format of an entry is as follows:
; highest address -> length:word (may be 0)
; key to replace:word (either hi or low byte is zero)
; .
; . new key value, "length" bytes long
; .
; lowest address -> next entry, or free space.
; If no arguments are given, keyboard is reset to default condition.
; Otherwise, first parameter (or first two, if first is zero) defines
; the key whose value is to be changed, and the following parameters
; define the key's new, possibly zero-length, value.
key:
; Is this a reset?
or cx, cx
jz key_init
; Get the first (or first two) parameters
cld
dec si ; point to first param
dec cx ; Assume it's a fn key, get two params
dec cx
lodsw
or al, al ; Is it a function key?
jz key_fnkey
; It's not a function key- put second param back
inc cx
dec si
key_fnkey:
; Key to redefine now in AX. If it's already redefined,
; lookup will set Z, point SI to redef string, set CX to its length.
push di
push es
push cx
push si
std ; moving up, must move from top down
push ds
pop es ; string move must have ES=DS
call lookup ; rets Z if redefined...
jnz key_newkey
; It's already defined. Erase its old definition- i.e., move
; region param_end+1..SI-1 upwards CX+4 bytes, add CX+4 to param_end.
add cx, 4
mov bp, param_end ; save old value in bp...
add param_end, cx
dec si ; start at (SI-1)
mov di, si
add di, cx ; move to (start + CX+4)
mov cx, si
sub cx, bp ; length of region old_param_end+1..start
rep movsb
key_newkey:
; Key not redefined. See if there's enough room to redefine it.
pop si ; get back pointer to redef string
pop cx ; get back number of bytes in redef string
mov di, param_end ; hi byte of new redef record, hi byte of len
sub di, 4 ; hi byte of new data field
mov bx, di
sub bx, cx ; hi byte of remaining buffer space
sub bx, 16 ; better be at least 16 bytes room
cmp bx, param_buffer
jb key_popem ; nope- forget it.
; Nothing in the way now!
mov [di+3], cx ; save length field
mov [di+1], ax ; save name field
jcxz key_nullstring
key_saveloop: ; save data field
movsb
add si, 2 ; input string ascending, output descending
loop key_saveloop
key_nullstring:
mov param_end, di ; save adr of new hi byte of free area
key_popem:
pop es
pop di
key_exit:
cld
ret
key_init:
; Build the default redefinition table:
; control-printscreen -> control-P
push es
push ds
pop es
std
mov di, redef_end
mov ax, 1
stosw
mov ax, 7200h ; control-printscreen
stosw
mov al, 16 ; control P
stosb
mov param_end, di ; save new bottom of redef table
pop es
jmp key_exit
;---- Delete/Insert Lines -------------------------------
; AL is number of lines to delete/insert.
; Preserves DX, DI; does not move cursor.
d_l: ; Delete lines.
mov ah, 6 ; BIOS: scroll up
jmp short il_open
il: ; Insert lines.
mov ah, 7 ; BIOS: scroll down
il_open:
; Whether inserting or deleting, limit him to (max_y - cur_y) lines;
; if above that, we're just clearing; set AL=0 so BIOS doesn't burp.
mov bh, max_y
sub bh, cur_y
cmp al, bh
jbe il_ok ; DRK 9/4...
mov al, 0 ; he tried to move too far
il_ok:
push ax
call get_blank_attrib
mov bh, ah ; color to use on new blank areas
pop ax ; AL is number of lines to scroll.
mov cl, 0 ; upper-left-x of data to scroll
mov ch, cur_y ; upper-left-y of data to scroll
push dx
mov dl, max_x ; lower-rite-x
mov dh, max_y ; lower-rite-y (zero based)
int 10h ; call BIOS to scroll a rectangle.
pop dx
ret ; done.
;-- Insert / Delete Characters ----------------------------
; AL is number of characters to insert or delete.
; Preserves DX, DI; does not move cursor.
ic: mov ch, 1 ; 1 => swap dest & source below
jmp short dc_ch
dc: mov ch, 0
dc_ch:
call in_g_mode
jnc dc_ret ; | if in graphics mode, ignore.
; AL = number of chars to ins or del (guarenteed nonzero).
; Limit him to # of chars left on line.
cmp al, dl
jbe dc_cok
mov al, dl
dc_cok:
push di ; DI is current address of cursor
xchg ax, cx ; CX gets # of chars to ins/del
mov bp, cx ; BP gets # of columns to clear.
; Set up source = destination + cx*2, count = dx - cx
mov ch, 0 ; make it a word
mov si, di
add si, cx
add si, cx
neg cl
add cl, dl
mov ch, 0 ; CX = # of words to transfer
cld ; REP increments si & di
; If this is an insert, then flip transfer around in both ways.
test ah, 1
jz dc_noswap
xchg di, si ; source <-> dest
std ; up <-> down
mov ax, cx ; make move over same range
dec ax
add ax, ax ; AX=dist from 1st to last byte.
add di, ax ; Start transfer at high end of block
add si, ax ; instead of low end.
dc_noswap:
; Move those characters.
push es
pop ds
rep movsw
mov cx, bp
; Figure out what color to make the new blanks.
call get_blank_attrib
mov al, ' '
; Blank out vacated region.
rep stosw
; All done.
cld ; restore normal REP state and
pop di ; cursor address.
dc_ret: ret
;---- set / reset mode ---------------------------------------
; Sets graphics/text mode; also sets/resets "no wrap at eol" mode.
sm: mov cl, 0ffh ; set
sm_rs:
; Is it "wrap at eol" ?
cmp al, 7
jnz sm_notwrap
mov wrap_flag, cl ; true = wrap at EOL
jmp short sm_done
sm_notwrap:
; Is it "set highest number of screen lines available"?
cmp al, 43
jnz sm_video
; Only valid for the Enhanced Graphics Adaptor on
; a monochrome display or an enhanced color display.
; Test presence of EGA by calling BIOS fn 12h.10h.
mov ah, 12h
mov bx, 0ff10h
int 10h ; bh=0-1, bl=0-3 if EGA
test bx, 0FEFCH
jnz sm_done ; sorry, charlie
; mov port_6845, 3d4h
; mov al, video_mode
; and al, 7
; cmp al, 7 ; monochrome monitor?
; jnz sm_colormon
; mov byte ptr port_6845, low(3b4h)
;sm_colormon:
; 43 line mode only allowed in text modes, for now.
call in_g_mode
jnc sm_done
mov ah, 0 ; "Set video mode"
mov al, video_mode ; Re-init current mode
int 10h
mov ax,1112h ; Load 8x8 font
mov bl,0 ; (instead of 8x14)
int 10h
mov ax, 1200h ; Load new printscreen
mov bl, 20h
int 10h
mov ah,1
mov cx,0707h ; (Load cursor scan lines)
int 10h
; | Patch; this gotten by painful observation of
; | IBM's professional editor. I think there's a
; | documented bug in Video Bios's "load cursor scan line"
; | call; try looking in latter 1985 PC Tech Journal.
mov dx, port_6845 ; '6845' command reg
mov al, 10
out dx, al
jmp $+2
inc dx
mov al, 7
out dx, al ; set cursor start line
; Assume that gets us 43 lines.
mov max_y, 42
jmp short sm_home
sm_video:
; It must be a video mode. Call BIOS.
mov ah, 0 ; "set video mode"
int 10h
; Assume that gets us 25 lines.
mov max_y, 24
sm_home:
; Read the BIOS buffer address/cursor position variables.
mov ax, abs40
push ds
mov ds, ax
assume ds:abs40
; Find current video mode and screen size.
mov ax,word ptr crt_mode ; al = crt mode; ah = # of columns
pop ds
mov video_mode, al
dec ah ; ah = max column
mov max_x, ah
; Since cursor may end up in illegal position, it's best to
; just go home after switching video modes.
mov cur_coords, 0
call xy_to_regs
sm_done:
ret
rm: mov cl, 0 ; reset
jmp sm_rs
;------- Output Character Translation ----------------------
; A decidedly nonstandard function, possibly useful for editing files
; intended to be printed by daisywheel printers with strange wheels.
; (The letter 'y' was chosen to conflict with the VT100 self-test command.)
; Usage: ESC [ #1;#2 y
; where #1 is the character to redefine
; #2 is the new display value
; If only ESC [ #1 y is sent, character #1 is reset to its default value.
; If only ESC [ y is sent, the entire table is reset to the default value.
; (If only ESC [ #1; y is sent, character #1 is set to zero... sigh.)
xoc: ; Xlate output character
mov bx, xlate_tab_ptr
jcxz xoc_reset ; if no parameters, reset table to 1:1
dec si ; point to first parameter
lodsw ; first parameter to AL, second to AH
dec cx ; is parameter count 1?
jnz xoc_bothparams
mov ah, al ; if only one param, reset that char.
xoc_bothparams:
add bl, al
adc bh, 0 ; bx points to entry for char AL
mov byte ptr [bx], ah ; change that entry
xoc_done:
ret
xoc_reset:
; Fill table with default values- i.e. 0, 1, 2, ... 255.
xor ax, ax
xoc_loop:
mov byte ptr [bx], al
inc bx
inc al
jnz xoc_loop
jmp xoc_done
ansi_functions endp ; end dummy procedure block
;-------- Color table -----------------------------------------
; Used in "set graphics rendition"
colors equ 22 ; number of colors in table
color_table:
db 0, 000h,07h ; all attribs off; normal.
db 1, 0ffh,08h ; bold
db 4, 0f8h,01h ; underline
db 5, 0ffh,80h ; blink
db 7, 0f8h,70h ; reverse
db 8, 088h,00h ; invisible
db 30,0f8h,00h ; black foreground
db 31,0f8h,04h ; red
db 32,0f8h,02h ; green
db 33,0f8h,06h ; yellow
db 34,0f8h,01h ; blue
db 35,0f8h,05h ; magenta
db 36,0f8h,03h ; cyan
db 37,0f8h,07h ; white
db 40,08fh,00h ; black background
db 41,08fh,40h ; red
db 42,08fh,20h ; green
db 43,08fh,60h ; yellow
db 44,08fh,10h ; blue
db 45,08fh,50h ; magenta
db 46,08fh,30h ; cyan
db 47,08fh,70h ; white
code ends
end ; of nansi_f.asm
page 66, 132
SHAR_EOF
if test 16524 -ne "`wc -c < 'nansi_f.asm'`"
then
echo shar: error transmitting "'nansi_f.asm'" '(should have been 16524 characters)'
fi
fi # end of overwriting check
if test -f 'nansi_i.asm'
then
echo shar: will not over-write existing file "'nansi_i.asm'"
else
cat << \SHAR_EOF > 'nansi_i.asm'
;------ nansi_i.asm ----------------------------------------------
; Contains code only needed at initialization time.
; (C) 1986 Daniel Kegel
; May be distributed for educational and personal use only
;-----------------------------------------------------------------
include nansi_d.asm ; definitions
; to nansi.asm
public dosfn0
; from nansi.asm
extrn break_handler:near
extrn int_29:near
if takeBIOS
extrn new_vid_bios:near
extrn old_vid_bios:dword
endif
extrn req_ptr:dword
extrn xlate_tab_ptr:word
; from nansi_p.asm
extrn param_buffer:word ; adr of first byte free for params
extrn param_end:word ; adr of last byte used for params
extrn redef_end:word ; adr of last used byte for redefs
code segment byte public 'CODE'
assume cs:code, ds:code
;-------- dos function # 0 : init driver ---------------------
; Initializes device driver interrupts and buffers, then
; passes ending address of the device driver to DOS.
; Since this code is only used once, the buffer can be set up on top
; of it to save RAM.
dosfn0 proc near
; Install BIOS keyboard break handler.
xor ax, ax
mov ds, ax
mov bx, 6Ch
mov word ptr [BX],offset break_handler
mov [BX+02], cs
; Install INT 29 quick putchar.
mov bx, 0a4h
mov word ptr [bx], offset int_29
mov [bx+2], cs
if takeBIOS
; Install INT 10h video bios replacement.
mov bx, 40h
mov ax, [bx]
mov word ptr cs:old_vid_bios, ax
mov ax, [bx+2]
mov word ptr cs:old_vid_bios[2], ax
mov word ptr [bx], offset new_vid_bios
mov word ptr [bx+2], cs
endif
push cs
pop ds
push cs
pop es ; es=cs so we can use stosb
cld ; make sure stosb increments di
; Calculate addresses of start and end of parameter/redef buffer.
; The buffer occupies the same area of memory as this code!
; ANSI parameters are accumulated at the lower end, and
; keyboard redefinitions are stored at the upper end; the variable
; param_end is the last byte used by params (changes as redefs added);
; redef_end is the last word used by redefinitions.
mov di, offset dosfn0
mov param_buffer, di
add di, 512
mov param_end, di ; addr of last byte in free area
inc di
; Build the default redefinition table:
; control-printscreen -> control-P
; (Must be careful not to write over ourselves here!)
mov al, 16 ; control P
stosb
mov ax, 7200h ; control-printscreen
stosw
mov ax, 1 ; length field
mov redef_end, di ; address of last used word in table
stosw
; Build a 1:1 output character translation table.
; It is 256 bytes long, starts just after the param/redef buffer,
; and is the last thing in the initialized device driver.
mov xlate_tab_ptr, di
xor ax, ax
init_loop:
stosb
inc al
jnz init_loop
xor ax, ax
; Return ending address of this device driver.
; Status is in AX.
lds si, req_ptr
mov word ptr [si+0Eh], di
mov [si+10h], cs
; Return exit status in ax.
ret
dosfn0 endp
code ends
end ; of nansi_i.asm
SHAR_EOF
if test 2913 -ne "`wc -c < 'nansi_i.asm'`"
then
echo shar: error transmitting "'nansi_i.asm'" '(should have been 2913 characters)'
fi
fi # end of overwriting check
if test -f 'nansi_p.asm'
then
echo shar: will not over-write existing file "'nansi_p.asm'"
else
cat << \SHAR_EOF > 'nansi_p.asm'
;----- nansi_p.asm --------------------------------------------------------
; A state machine implementation of the mechanics of ANSI terminal control
; string parsing.
; (C) 1986 Daniel Kegel, Pasadena, CA
; May be distributed for educational and personal use only
;
; Entered with a jump to f_escape when driver finds an escape, or
; to f_in_escape when the last string written to this device ended in the
; middle of an escape sequence.
;
; Exits by jumping to f_ANSI_exit when an escape sequence ends, or
; to f_not_ANSI when a bad escape sequence is found, or (after saving state)
; to f_loopdone when the write ends in the middle of an escape sequence.
;
; Parameters are stored as bytes in param_buffer. If a parameter is
; omitted, it is stored as zero. Each character in a keyboard reassignment
; command counts as one parameter.
;
; When a complete escape sequence has been parsed, the address of the
; ANSI routine to call is found in ansi_fn_table.
;
; Register usage during parsing:
; DS:SI points to the incoming string.
; CX holds the length remaining in the incoming string.
; ES:DI points to the current location on the memory-mapped screen.
; DX is number of characters remaining on the current screen line.
; BX points to the current paramter byte being assembled from the incoming
; string. (Stored in cur_parm_ptr between device driver calls, if needed.)
;
; The registers are set as follows before calling the ANSI subroutine:
; AX = max(1, value of first parameter)
; CX = number of paramters
; SI = offset of second parameter from CS
; DS = CS
; ES:DI points to the current location on the memory-mapped screen.
; DX is number of characters remaining on the current screen line.
; The subroutine is free to trash AX, BX, CX, SI, and DS.
; It must preserve ES, and can alter DX and DI if it wants to move the
; cursor.
;
; Revision history:
; 7 July 85: created by DRK
;------------------------------------------------------------------------
; From nansi.asm
extrn f_not_ANSI:near ; exit: abort bad ANSI cmd
extrn f_ANSI_exit:near ; exit: good cmd done
extrn f_loopdone:near ; exit: ran out of chars. State saved.
extrn escvector:word ; saved state: where to jump
extrn cur_parm_ptr:word ; saved state: where to put next param
extrn string_term:byte ; saved state: what ends string
extrn cur_x:byte, max_x:byte ; 0 <= cur_x <= max_x
extrn cur_attrib:byte ; current color/attribute
extrn xlate_tab_ptr:word
; from nansi_f.asm
extrn ansi_fn_table:word ; ANSI subroutine table
; Used in nansi.asm
public f_escape ; entry: found an escape
public f_in_escape ; entry: restore state, keep parsing
; Used in nansi_i.asm and nansi_f.asm
public param_buffer, param_end, redef_end
code segment byte public 'CODE'
assume cs:code
; More saved state
in_num db ? ; true if between a digit and a semi in parse
param_buffer dw 3000h ; address of first byte free for new params
param_end dw 3030h ; address of end of free area
redef_end dw 3030h ; address of end of redefinition area
; These initialized values are only for debugging
;----- next_is -------------------------------------------------------
; Next_is is used to advance to the next state. If there are characters
; left in the input string, we jump immediately to the new state;
; otherwise, we shut down the recognizer, and wait for the next call
; to the device driver.
next_is macro statename
loop statename
mov ax, offset statename
jmp sleep
endm
;----- sleep --------------------------------------------------------
; Remember bx and next state, then jump to device driver exit routine.
; Device driver will re-enter at f_in_escape upon next invocation
; because escvector is nonzero; parsing will then be resumed.
sleep: mov cs:cur_parm_ptr, bx
mov cs:escvector, ax
jmp f_loopdone
;----- f_in_escape ---------------------------------------------------
; Main loop noticed that escvector was not zero.
; Recall value of BX saved when sleep was jumped to, and jump into parser.
f_in_escape:
mov bx, cs:cur_parm_ptr
jmp word ptr cs:escvector
fbr_syntax_error_gate: ; jumped to from inside f_bracket
jmp syntax_error
;----- f_escape ------------------------------------------------------
; We found an escape. Next character should be a left bracket.
f_escape:
next_is f_bracket
;----- f_bracket -----------------------------------------------------
; Last char was an escape. This one should be a [; if not, print it.
; Next char should begin a parameter string.
f_bracket:
lodsb
cmp al, '['
jnz fbr_syntax_error_gate
; Set up for getting a parameter string.
mov bx, cs:param_buffer
mov byte ptr cs:[bx], 0
mov cs:in_num, 0
next_is f_get_args
;----- f_get_args ---------------------------------------------------
; Last char was a [. If the current char is a '=' or a '?', eat it.
; In any case, proceed to f_get_param.
; This is only here to strip off the strange chars that follow [ in
; the SET/RESET MODE escape sequence.
f_get_args:
lodsb
cmp al, '='
jz fga_ignore
cmp al, '?'
jz fga_ignore
dec si ; let f_get_param fetch al again
jmp short f_get_param
fga_ignore:
next_is f_get_param
;----- f_get_param ---------------------------------------------------
; Last char was one of the four characters "]?=;".
; We are getting the first digit of a parameter, a quoted string,
; a ;, or a command.
f_get_param:
lodsb
cmp al, '0'
jb fgp_may_quote
cmp al, '9'
ja fgp_may_quote
; It's the first digit. Initialize current parameter with it.
sub al, '0'
mov byte ptr cs:[bx], al
mov cs:in_num, 1 ; set flag for sensing at cmd exec
next_is f_in_param
fgp_may_quote:
cmp al, '"'
jz fgp_isquote
cmp al, "'"
jnz fgp_semi_or_cmd ; jump to code shared with f_in_param
fgp_isquote:
mov cs:string_term, al ; save it for end of string
next_is f_get_string ; and read string into param_buffer
;----- f_get_string -------------------------------------
; Last character was a quote or a string element.
; Get characters until ending quote found.
f_get_string:
lodsb
cmp al, cs:string_term
jz fgs_init_next_param
mov byte ptr cs:[bx], al
cmp bx, cs:param_end
adc bx, 0 ; if bx<param_end bx++;
next_is f_get_string
; Ending quote was found.
fgs_init_next_param:
mov byte ptr cs:[bx], 0 ; initialize new parameter
; | Eat following semicolon, if any.
next_is f_eat_semi
;----- f_eat_semi -------------------------------------
; Last character was an ending quote.
; If this char is a semi, eat it; else unget it.
; Next state is always f_get_param.
f_eat_semi:
lodsb
cmp al, ';'
jz fes_eaten
inc cx
dec si
fes_eaten:
next_is f_get_param
;----- syntax_error ---------------------------------------
; A character was rejected by the state machine. Exit to
; main loop, and print offending character. Let main loop
; decrement CX (length of input string).
syntax_error:
mov cs:escvector, 0
mov ah, cs:cur_attrib
mov bx, cs:xlate_tab_ptr
jmp f_not_ANSI ; exit, print offending char
;------ f_in_param -------------------------------------
; Last character was a digit.
; Looking for more digits, a semicolon, or a command character.
f_in_param:
lodsb
cmp al, '0'
jb fgp_semi_or_cmd
cmp al, '9'
ja fgp_semi_or_cmd
; It's another digit. Add into current parameter.
sub al, '0'
xchg byte ptr cs:[bx], al
push dx
mov dl, 10
mul dl
pop dx
add byte ptr cs:[bx], al
next_is f_in_param
; Code common to states get_param and in_param.
; Accepts a semicolon or a command letter.
fgp_semi_or_cmd:
cmp al, ';'
jnz fgp_not_semi
cmp bx, cs:param_end ; prepare for next param-
adc bx, 0 ; if bp<param_end bp++;
; Set new param to zero, enter state f_get_param.
mov cs:in_num, 0 ; no longer inside number
jmp fgs_init_next_param ; spaghetti code attack!
fgp_not_semi:
; It must be a command letter.
cmp al, '@'
jb syntax_error
cmp al, 'z'
ja syntax_error
cmp al, 'Z'
jbe fgp_is_cmd
cmp al, 'a'
jb syntax_error
; It's a lower-case command letter.
; Remove hole between Z and a to save space in table.
sub al, 'a'-'['
fgp_is_cmd:
; It's a command letter. Save registers, convert letter
; into address of routine, set up new register usage, call routine.
push si ; These three registers hold info
push cx ; having to do with the input string,
push ds ; which has no interest at all to the
; control routine.
push cs
pop ds ; ds is now cs
sub al, '@' ; first command is @: insert chars
cbw
add ax, ax
add ax, offset ansi_fn_table
; ax is now pointer to command routine address in table
mov cx, bx
mov si, param_buffer ; si is now pointer to parameters
sub cx, si ;
test in_num, 1
jz fip_out_num
inc cx
fip_out_num: ; cx is now # of parameters
xchg ax, bx ; save pointer to routine in bx
; Calculate cur_x from DX.
mov al, max_x
inc ax
sub al, dl
mov cur_x, al
; Get first parameter into AX; if defaulted, set it to 1.
mov ah, 0
lodsb
or al, al
jnz fgp_callem
inc ax
fgp_callem:
; Finally, call the command subroutine.
call word ptr [bx]
pop ds
pop cx
pop si
mov ah, cs:cur_attrib ; Prepare for STOSW.
mov bx, cs:xlate_tab_ptr ; Prepare for translation.
mov cs:escvector, 0 ; No longer parsing escape sequence.
; Set flags for reentry at loopnz
or dx, dx ; "Any columns left on line?"
; Re-enter at bottom of main loop.
jmp f_ansi_exit
code ends
end ; of nansi_p.asm
page 66, 132
SHAR_EOF
if test 9398 -ne "`wc -c < 'nansi_p.asm'`"
then
echo shar: error transmitting "'nansi_p.asm'" '(should have been 9398 characters)'
fi
fi # end of overwriting check
if test -f 'setraw.asm'
then
echo shar: will not over-write existing file "'setraw.asm'"
else
cat << \SHAR_EOF > 'setraw.asm'
;---- setraw.asm ----------------------------------------------
public getraw, setraw
;----- dos ----------------------
; Call DOS function # n.
dos macro fn
mov ah, fn
int 21h
endm
code segment para public 'CODE'
assume cs:code
;----- Getraw ---------------------------------------------
; Returns AX=1 if file BX is a device in raw mode; 0 otherwise.
; Returns Carry set & errorcode in AX if DOS error.
getraw proc near
mov al, 0
DOS 44h ; Get attributes
jc gr_exit ; bad file handle?
mov ax, 20h
and al, dl ; get that bit
mov cl, 4
shr ax, cl
clc
gr_exit:
ret
getraw endp
;----- Setraw -------------------------------------------
; Sets Raw state of file BX to (AX != 0) if file is a device.
; Returns Carry set & errorcode in AX if DOS error.
setraw proc near
mov cx, ax
mov al, 0
DOS 44h
jc sr_exit
test al, 80h ; It it a device?
jz sr_exit ; nope- do nothing.
; Current mode in DX; set CX = 20H if CX nonzero.
or cx, cx
jz sr_ax0
mov cx, 20h
sr_ax0: and dx, 00cfh ; clear old raw bit and hi byte,
or dx, cx ; set new value.
mov al, 1
DOS 44h
sr_exit:
ret
setraw endp
code ends
end
;---- end of setraw.asm ------------------------------------------
SHAR_EOF
if test 1192 -ne "`wc -c < 'setraw.asm'`"
then
echo shar: error transmitting "'setraw.asm'" '(should have been 1192 characters)'
fi
fi # end of overwriting check
if test -f 'setraw.lc'
then
echo shar: will not over-write existing file "'setraw.lc'"
else
cat << \SHAR_EOF > 'setraw.lc'
/*------ setraw.lc ----------------------------------------------
Lattice C routines which get and set the current raw/cooked state
of a file, given its Lattice file descriptor.
Useful when trying to obtain high console output speeds.
----------------------------------------------------------------*/
#include "\lc\dos.h"
#define CARRY 0x1
#define ERROR (-1)
#define TRUE 1
#define FALSE 0
extern _oserr;
/*---- getraw --------------------------------------------------
Returns TRUE if file fd is a device in raw mode; FALSE otherwise.
Returns ERROR, puts errorcode in _oserr, if DOS error.
----------------------------------------------------------------*/
getraw(fd)
int fd;
{
union REGS inregs;
union REGS outregs;
int flags;
if (fd > 2) fd+=2; /* convert to DOS fd */
inregs.x.bx = fd;
inregs.x.ax = 0x4400; /* get file attributes */
flags = intdos(&inregs, &outregs);
if (flags & CARRY) {
_oserr = outregs.x.ax;
return -1;
}
return (outregs.x.dx & 0x20) ? TRUE : FALSE;
}
/*---- setraw --------------------------------------------------
Sets Raw state of file fd to raw_on (if file is not a device, does nothing).
Returns zero if successful.
Returns ERROR & errorcode in _oserr if DOS error.
----------------------------------------------------------------*/
setraw(fd, raw_on)
int fd, raw_on;
{
union REGS inregs;
union REGS outregs;
int flags;
if (fd > 2) fd+=2; /* convert to DOS fd */
inregs.x.ax = 0x4400; /* get file attributes */
inregs.x.bx = fd;
flags = intdos(&inregs, &outregs);
if (flags & CARRY) {
_oserr = outregs.x.ax;
return ERROR;
}
if ((outregs.x.ax & 0x80) == 0) /* return zero if not device */
return 0;
outregs.x.ax = 0x4401; /* set file attributes */
outregs.x.bx = fd;
outregs.x.dx &= 0xcf; /* clear old raw bit & hi byte */
if (raw_on) outregs.x.dx |= 0x20; /* maybe set new raw bit */
flags = intdos(&outregs, &inregs);
if (flags & CARRY) {
_oserr = inregs.x.ax;
return ERROR;
}
return 0;
}
/*-- end of setraw.lc --*/
/*------ rawtest.lc -------------------------------------------------
Lattice C program to demonstrate the difference in speed between
DOS's raw and cooked modes when writing to the DOS console.
Requires setraw.c; make the demo as follows:
lc setraw rawtest
link \lc\s\c rawtest setraw,rawtest,,\lc\s\lc
and run it by typing
rawtest
Note- Lattice C's raw mode (i.e. using mode "rb" or "wb" with fopen)
is not the same as DOS's raw mode, and does not affect speed.
What does affect speed is whether output is performed with single-character
DOS calls, which is the default. To get a speed improvement, you must
open "con" WITHOUT a trailing colon, and use that file for high-speed output;
see section 5.2 (Device I/O) of the Lattice manual.
When using MS-DOS raw mode, the console is in totally unbuffered mode-
echo is turned off, no printer echoing is done, and no line editing
is done, regardless of which file setraw was applied to. This means
that the console must be in non-raw ("cooked") mode for line-oriented
console input to work properly.
Note: no speed difference will be noticed when using the standard console
driver ANSI.SYS that comes with DOS; you must be using NANSI.SYS to
get massively fast output.
To use nansi.sys, insert the following line in \config.sys:
device = nansi.sys
and put nansi.sys on the top level directory; the system will load
it at boot time.
(If there was already a line invoking plain old ansi.sys, remove it.)
--------------------------------------------------------------------*/
#include "\lc\stdio.h"
char response[128];
main(argc, argv)
int argc;
char **argv;
{
FILE *fp;
int fd;
int old_rawness;
int i;
fp = fopen("con", "w");
if (fp == NULL) fprintf(stderr, "can't open 'con'!");
fd = fileno(fp); /* get Level 1 file descriptor */
old_rawness = getraw(fd); /* Save old raw/cooked state */
setraw(fd, 0); /* make sure we're in cooked mode */
puts("Cooked mode test (hit return):");
gets(response);
fprintf(fp, "\033[2J"); /* clear screen */
for (i=0; i<20; i++)
fprintf(fp, "This is cooked mode! Why is it so darned slow? %d\n", i);
fflush(fp);
puts("Raw mode test (hit return):");
gets(response); /* must be in cooked mode to use gets */
setraw(fd, 1); /* enter raw mode */
fprintf(fp, "\033[2J"); /* clear screen */
for (i=0; i<20; i++)
fprintf(fp, "-- This is raw mode- it's clearly faster than cooked! %d\n", i);
fflush(fp); /* finish writing while in raw mode */
setraw(fd, old_rawness); /* go back to old raw/cooked state */
fclose(fp);
}
/*--- end of rawtest.lc ---*/
SHAR_EOF
if test 4586 -ne "`wc -c < 'setraw.lc'`"
then
echo shar: error transmitting "'setraw.lc'" '(should have been 4586 characters)'
fi
fi # end of overwriting check
if test -f 'setraw.msc'
then
echo shar: will not over-write existing file "'setraw.msc'"
else
cat << \SHAR_EOF > 'setraw.msc'
/*--- setraw.msc -------------------------------------------------
Routines to set and reset raw mode on stdin/stdout.
For Microsoft C.
------------------------------------------------------------------*/
#include <dos.h>
/* Use the IOCTL DOS function call to change stdin and stdout to raw mode.
* For stdin, this prevents MSDOS from trapping ^P, ^S, ^C, thus freeing us
* of ^P toggling 'echo to printer'.
* For stdout, this radically speeds up the output because there is no
* checking for these special characters in the input buffer whenever
* screen output is occurring.
* Note that only the stdin OR stdout ioctl need be changed since
* apparently they are handled as the same device.
* Thanks to Mark Zbikowski (markz at microsoft.UUCP) for helping me with
* this.
* --- This stolen from sources to the mighty game HACK ---
*/
#define DEVICE 0x80
#define RAW 0x20
#define IOCTL 0x44
#define STDIN fileno(stdin)
#define STDOUT fileno(stdout)
#define GETBITS 0
#define SETBITS 1
static unsigned old_stdin, old_stdout, ioctl();
/*--- set_raw() ----------
Call this to set raw mode; call restore_raw() later to restore
console to old rawness state.
--------------------------*/
set_raw()
{
old_stdin = ioctl(STDIN, GETBITS, 0);
old_stdout = ioctl(STDOUT, GETBITS, 0);
if (old_stdin & DEVICE)
ioctl(STDIN, SETBITS, old_stdin | RAW);
if (old_stdout & DEVICE)
ioctl(STDOUT, SETBITS, old_stdout | RAW);
}
restore_raw()
{
if (old_stdin)
(void) ioctl(STDIN, SETBITS, old_stdin);
if (old_stdout)
(void) ioctl(STDOUT, SETBITS, old_stdout);
}
static unsigned
ioctl(handle, mode, setvalue)
unsigned setvalue;
{
union REGS regs;
regs.h.ah = IOCTL;
regs.h.al = mode;
regs.x.bx = handle;
regs.h.dl = setvalue;
regs.h.dh = 0; /* Zero out dh */
intdos(®s, ®s);
return (regs.x.dx);
}
/*-- end of setraw.msc --*/
SHAR_EOF
if test 1854 -ne "`wc -c < 'setraw.msc'`"
then
echo shar: error transmitting "'setraw.msc'" '(should have been 1854 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Comp.sources.unix
mailing list