MS-DOS Kermit sources (Part 4 of 7)
Jim Knutson
knutson at ut-ngp.UUCP
Sat Oct 6 02:07:20 AEST 1984
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting msterm.asm'
sed 's/^X//' <<'//go.sysin dd *' >msterm.asm
public clscpt, defkey, cptfcb, inicpt, clscpi, telnet
public dopar, shokey, prkey
include msdefs.h
datas segment public 'datas'
extrn flags:byte, trans:byte, buff:byte, portval:word
targ termarg <0,1,80,24,cptchr,2dch,0,scntab,deftab,0,,parnon>
ssp dw 0 ; Save SP in Telnet.
crlf db cr,lf,'$'
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
tmsg1 db cr,lf,'[Connecting to host, type $'
tmsg3 db ' C to return to PC]',cr,lf,cr,lf,cr,lf,'$'
tmsg2 db cr,lf,'[Back at micro]',cr,lf,'$'
erms22 db cr,lf,'?No capture file open$' ;[jd]
esctl db 'Control-$' ; [6]
inthlp db cr,lf,' ? This message'
db cr,lf,' C Close the connection'
db cr,lf,' S Status of the connection'
db cr,lf,' B Send a break'
db cr,lf,' M Toggle mode line'
db cr,lf,' Q Quit logging'
db cr,lf,' R Resume logging'
db cr,lf,' 0 Send a null'
db cr,lf,' Typing the escape character will send it to the host'
db 0
intprm db 'Command>$'
CPTFCB DB 25H DUP (?)
CAPBUF DB 200 DUP (?)
CAPBP DW ?
CAPLFT DB ?
SCNTLEN EQU 200 ; MAX # OF DEFINITIONS ONE can have
defbsiz equ 400 ; combined length of all definitions...
scntab dw scntlen dup (?) ; scan codes redefined
deftab dw scntlen dup (?) ; pointer to definition strings
defbuf db defbsiz dup (?)
defptr dw defbuf ; pointer starts at beginning
deflen dw defbsiz ; amt of space left in buffer
sttmsg db 'Type space to continue$'
shkmsg db cr,lf,'Press key: $'
datas ends
code segment public
extrn comnd:near, outchr:near, stat0:near
extrn escprt:near, clrbuf:near, term:near
extrn cmblnk:near, locate:near, prtchr:near
extrn beep:near, puthlp:near
extrn serini:near,serrst:near, sendbr:near, showkey:near
assume cs:code, ds:datas
; the show key command.
shokey proc near
mov ah,cmcfm ; confirm with carriage return
call comnd
jmp r ; uh oh...
mov dx,offset shkmsg
mov ah,prstr
int dos ; print a prompt for it
mov ax,offset targ ; give it terminal arg block.
call showkey ; show them the key definition
push ax
push cx ; save results
mov dx,offset crlf
mov ah,prstr
int dos
pop cx
pop ax
call prkey ; print the buffer
mov dx,offset crlf
mov ah,prstr
int dos
jmp rskp ; and return
shokey endp
; pass a string pointer in ax, length in cx.
; Prints the string, quoting any unprintables, except crlf.
prkey proc near
mov si,ax ; copy string ptr
jcxz prke6 ; no string, stop here
prke1: push cx ; save counter
lodsb ; get a byte
and al,7fH ; only consider low-order 7 bits.
cmp al,' ' ; printable?
jb prke2 ; no, print the hard way
cmp al,7fH ; maybe a delete?
jne prke4 ; no, can just put into string
prke2: jcxz prke3 ; last char, can't be crlf
cmp al,cr ; carriage return?
jne prke3 ; no, go on
cmp byte ptr [si],lf ; followed by linefeed?
jne prke3
mov ah,prstr
mov dx,offset crlf
int dos ; else just print crlf
inc si ; skip over lf
pop cx ; careful...
dec cx
push cx
jmp short prke5
prke3: push ax ; preserve the char
mov ah,conout
mov dl,'\'
int dos ; print the quote character
pop ax
call proct ; print the octal byte
jmp short prke5
prke4: mov dl,al ; normal char, just print it
mov ah,conout
int dos
prke5: pop cx ; restore count
loop prke1
prke6: ret ; and return
prkey endp
; print the byte in al as an octal number
proct proc near
mov dl,al ; get the byte
and dl,7h ; keep low-order byte
mov cl,3
shr al,cl ; shift to get next digit
jz proc1 ; 0, no more to print
push dx ; else save current digit
call proct ; print rest
pop dx
proc1: mov ah,conout
add dl,'0' ; make printable
int dos
ret
proct endp
; This is the CONNECT command.
TELNET PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
mov ah,prstr ; Output
mov dx,offset crlf ; a crlf.
int dos
call domsg ; Reassure user. [19b]
mov al,targ.flgs ; get present flags
and al,modoff ; this is only one we can keep around
or al,havtt ; defaults (!)
cmp flags.debug,0 ; debug mode?
jz tel0 ; no, keep going
or al,trnctl ; yes, show control chars
tel0: cmp flags.vtflg,0 ; vt52 emulation?
jz tel1
or al,emheath
tel1: mov bx,portval
cmp [bx].ecoflg,0 ; echoing?
jz tel2
or al,lclecho
tel2: mov targ.flgs,al ; store flags
mov ah,flags.comflg
mov targ.prt,ah ; Port 1 or 2
mov ah,trans.escchr
mov targ.escc,ah
mov ah,[bx].parflg
mov targ.parity,ah
mov ax,[bx].baud
mov targ.baudb,al
mov ah,flags.capflg
and ah,capt
or targ.flgs,ah
call serini ; init serial port
tem: mov ax,offset targ ; Point to terminal arguments
call term
or targ.flgs,scrsam ; assume screen is the same.
intchr: mov ah,dconio ; Direct console I/O.
mov dl,0FFH ; Input.
int dos ; Get a char.
jz intchr ; no char, keep looking
mov ah,al
jz intchr ; If so, go until we get a char.
cmp ah,' ' ; space - ignore it
je tem
mov bh,ah ; Save the actual char.
and ah,not ('a'-'A') ; Convert to upper case.
or ah,40H ; convert ctl-char to actual char.
cmp ah,'C' ; Is it close?
jne intch1
call serrst ; reset serial port
jmp rskp ; and return
intch1: cmp ah,'S' ; Is it status?
jnz intch2
call stat0 ; If so, call stat0.
call puthlp ; put help on screen
mov dx,offset sttmsg
mov ah,prstr
int dos
intch1a:mov ah,8 ; console input, no echo
int dos
cmp al,' ' ; space?
jne intch1a
and targ.flgs,not scrsam ; remember screen changed.
jmp tem
intch2: cmp ah,'B' ; Send a break? [20g]
jne intch3 ; No. [20g]
call sendbr ; Yes, so send a break. [20g]
jmp tem ; And return. [20g]
intch3: cmp ah,'M' ; mode line?
jne intch4
xor targ.flgs,modoff ; toggle mode line
jmp tem ; and reconnect
intch4: cmp bh,'?' ; Is it help?
jne intch5 ; If not, go to the next check.
mov ax,offset inthlp ; If so, get the address of the help message.
call puthlp ; write help msg
mov dx,offset intprm
mov ah,prstr ; Print it.
int dos
and targ.flgs,not scrsam ; remember screen changed
jmp intchr ; Get another char.
intch5: cmp bh,trans.escchr ; Is it the escape char?
jne intch7 ; If not, go send a beep to the user.
intch6: mov ah,al
call outchr
nop
nop
nop
jmp tem ; Return, we are done here.
intch7: cmp ah,'Q' ; maybe want to stop logging?
jne intch8
test targ.flgs,capt ; not capturing, can't do this
jz intc10
and targ.flgs,not capt ; stop capturing
jmp tem ; and resume
intch8: cmp ah,'R' ; maybe resume?
jne intch9 ; no, keep going
cmp flags.capflg,0 ; can we capture?
jz intc10 ; no, forget it
test targ.flgs,capt ; already capturing?
jnz intc10 ; yes, can't toggle back on then
or targ.flgs,capt ; else turn flag on
jmp tem ; and resume
intch9: cmp bh,'0' ; perhaps want a null (note original chr in bh)
jne intc10
mov ah,0
call outchr
nop
nop
nop
jmp tem
intc10: call beep
jmp tem
TELNET ENDP
; Reassure user about connection to the host. Tell him what escape
; sequence to use to return and the communications port and baud
; rate being used. [19b]
DOMSG PROC NEAR
mov ah,prstr
mov dx,offset tmsg1
int dos
call escprt
mov ah,prstr
mov dx,offset tmsg3
int dos
ret
DOMSG ENDP
; Set parity for character in Register AL.
dopar: push bx
mov bx,portval
cmp [bx].parflg,parnon ; No parity? [10 start]
je parret ; Just return
cmp [bx].parflg,parevn ; Even parity?
jne dopar0
and al,07FH ; Strip parity.
jpe parret ; Already even, leave it.
or al,080H ; Make it even parity.
jmp parret
dopar0: cmp [bx].parflg,parmrk ; Mark parity?
jne dopar1
or al,080H ; Turn on the parity bit.
jmp parret
dopar1: cmp [bx].parflg,parodd ; Odd parity?
jne dopar2
and al,07FH ; Strip parity.
jpo parret ; Already odd, leave it.
or al,080H ; Make it odd parity.
jmp parret
dopar2: and al,07FH ; Space parity - turn off parity bit.
parret: pop bx
ret ; [10 end]
inicpt proc near
mov capbp,offset capbuf
mov caplft,128 ; init buffer ptr & chrs left
ret ; and return
inicpt endp
cptchr proc near ; capture routine, char in al
push di
mov di,capbp
mov byte ptr [di],al
inc di
mov capbp,di ; restore pointer
pop di
dec caplft ; decrement chars remaining
jnz cptch1 ; more room, forget this part
call cptdmp ; dump the info
call inicpt ; re-init ptrs.
cptch1: ret ; and return
cptchr endp
cptdmp proc near ; empty the capture buffer
push ax
push dx
mov ah,setdma
mov dx,offset capbuf ; the capture routine buffer
int dos
mov ah,writef
mov dx,offset cptfcb
int dos ; write out the block
;*** must be fixed... check error returns, disable capturing,
;*** figure out how to put dma address back
mov dx,offset buff
mov ah,setdma
int dos ; put dma back
pop dx
pop ax
ret
cptdmp endp
clscpt proc near
test flags.capflg,0FFH ; doing capture
jnz clscp1 ; yes, go ahead
mov dx,offset erms22
mov ah,prstr
int dos
jmp rskp
clscp1: mov ah,cmcfm
call comnd
jmp r
clscpi: mov al,'Z'-64 ; control-z for eof...
call cptchr ; output to file
mov al,caplft
cmp al,128 ; is buffer empty?
je clscp2 ; yes, forget this stuff
call cptdmp ; dump buffer (preserves registers)
clscp2: mov ah,0
sub word ptr cptfcb+16,ax ; subtract remaining from low filsize
sbb word ptr cptfcb+18,0 ; and from high size (with borrow)
mov ah,closf
mov dx,offset cptfcb
int dos ; close up file
mov flags.capflg,0 ; no longer capturing...
jmp rskp ; and return
clscpt endp
; enter with ax/scan code to define, si/ pointer to definition, cx/ length
; of definition. Defines it in definition table.
;*** somewhere should check for overflow etc of defbuf, and of scntab
defkey proc near
push ax ; save scan code
mov ax,ds
mov es,ax ; address data segment
mov di,defptr ; this is where the def gets built
inc di ; leave a byte for length
defk1: lodsb ; get a byte from the source
cmp al,'\' ; escape?
jne defk2 ; no, just deposit him
dec cx ; count available is one less
call trnesc ; translate the escape sequence
inc cx ; account for '\' (loop will decrement again).
defk2: stosb ; drop off character
loop defk1 ; and keep going while we have more
mov ax,di ; get ptr to end
dec ax ; back up pointer to end
mov si,defptr ; pick up old ptr value
sub ax,si ; this is actual length used
mov byte ptr [si],al ; fill in length of entry
mov defptr,di ; this is next free byte
; definition address is in si
pop ax ; recover scan code
mov cx,targ.klen ; length of scan table
jcxz defk4 ; not there, just go add it
mov di,offset scntab ; the scan code table
repne scasw ; look for this one
jne defk4 ; not defined already
sub di,offset scntab + 2 ; compute index into table
mov deftab[di],si ; fill in address
ret ; and return
defk4: mov di,targ.klen ; get length again
inc di
cmp di,scntlen
ja defk5 ;** ignore def if over size
mov targ.klen,di ; update length
shl di,1 ; double for word index
mov scntab[di-2],ax ; put scan code into table
mov deftab[di-2],si ; and fill in definition
defk5: ret ; that's it
defkey endp
; enter with si/ source pointer, cx/ count
; converts an escape sequence, updates all pointers
trnesc proc near
push bx
push dx ; preserve these
mov al,0 ; this is current accumulation
jcxz trnes2 ; empty string, forget it
mov bl,3 ; this is max # of digits to use
mov bh,8 ; this is radix
trnes1: mov dl,[si]
cmp dl,'0'
jb trnes2 ; out of range, stop here
cmp dl,'7'
ja trnes2
inc si ; accept character
sub dl,'0' ; convert to binary
mul bh ; shift accumulation
add al,dl ; add to accumulation
dec bl ; decrement digit counter
loopnz trnes1 ; and keep trying
trnes2: pop dx
pop bx
ret ; and return
trnesc endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msterm.asm
/bin/echo -n ' '; /bin/ls -ld msterm.asm
fi
/bin/echo 'Extracting msapc.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msapc.hlp
This note describes the capabilities of MS-DOS MSKermit as implemented for
the NEC Advanced Personal Computer (APC). The APC system dependent portion of
the code (both port and terminal handlers) resides in the file MSXAPC.ASM.
This is the only module required in addition to those that all implementations
need.
MSKermit on the APC supports both the standard serial port (as port 1) and
the optional (H14) add-on serial port (as port 2). Port selection is
performed using the SET PORT command. Any baud rate up to 38400 is legal
although 38400 has never been tested and may not work well. The port is
always configured as 8 data bits, no parity, and 1 stop bit. Any necessary
parity is supplied by Kermit.
The interrupt vector used by the optional port is jumper-selectable. Kermit
is set up to use IR8 by default, so if another vector is required the
MSXAPC.ASM file must be altered and reassembled. The changes are well
commented, and only amount to changing the value of a conditional.
Terminal mode support on the APC is relatively primitive. The only provisions
that have been made for emulation are in the operating system firmware, which
supports a limited subset of both VT100/ANSI and ADM-3A commands.
Two pages of screen memory and rollback are also provided by the firmware.
Control-uparrow scrolls back one line, while control-downarrow scrolls forward
a line.
Screen printing is performed by the CRTDUMP resident extension to MS-DOS
using the control-print command. The print (or control-P) key alone causes
Kermit to toggle echoing of the screen display to the printer.
Key redefinition is provided, but only for the keyboard keys. The function
keys must be defined using the system's KEY program. There is no direct
access to the keyboard's scan codes on the APC, so instead each key is
redefined by its ASCII value, limiting the usefulness of this function.
The default escape character is control-]. Bugs in the firmware prevent
this control sequence from being returned to the program, however, so it
is necessary to instead use the left arrow key which sends the control-]
code. Another alternative is to redefine the escape character in your
MSKERMIT.INI initialization file.
Despite these limitations, MSKermit for the APC is being released so that
the benefits of its file transfer capability are available to APC MS-DOS
users. It is to be hoped that these users will take it on themselves to
enhance the capabilities.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msapc.hlp
/bin/echo -n ' '; /bin/ls -ld msapc.hlp
fi
/bin/echo 'Extracting mskermit.hlp'
sed 's/^X//' <<'//go.sysin dd *' >mskermit.hlp
KERMIT VERSION 2.26 FOR MS-DOS AND PC-DOS
July 26, 1984
Kermit-MS is a program that provides terminal emulation and file trans-
fer for Intel 8088- and 8086-based microcomputers running the MS-DOS or
PC-DOS operating system. The Kermit file transfer protocol was
developed and the Kermit-MS program were developed at the Columbia
University Center for Computing Activities.
* Program Operation
Kermit-MS can be run interactively, from a batch file, or as an
"external" DOS command. Commands consist of one or more fields,
separated by "whitespace" -- one or more spaces or tabs. Upon startup,
the program executes any commands found in the file MSKERMIT.INI in the
current path.
X. Interactive Operation:
To run Kermit-MS interactively, invoke the program from DOS command
level by typing its name. When you see the command's prompt,
"Kermit-MS>", you may type Kermit commands repeatedly until you are
ready to exit the program. You can use these special characters while
typing commands.
BACKSPACE Delete the character most recently typed. May be typed
repeatedly to delete backwards. You may also use DELETE,
RUBOUT, or equivalent keys.
CTRL-W Delete the most recent "word", or field, on the command line.
May be typed repeatedly.
CTRL-U Delete the entire command line.
CTRL-C Cancel the current command and return to the "Kermit-MS>"
prompt.
? Type a brief message describing what you are expected to type in
the current field.
ESC If enough characters have been supplied in the current field
(keyword or file name) to uniquely identify it, supply the
remainder of the field and position to the next field of the
command. Otherwise, sound a beep.
= Wildcard character for matching single characters in filenames,
equivalent to MS-DOS "?".
X. Command Line Invocation:
Kermit-MS may also be invoked with command line arguments from DOS com-
mand level, for instance:
A>kermit send foo.bar
or
A>kermit set port 1, set baud 9600, connect
When invoked with command line arguments, Kermit-MS will behave as if it
were an external DOS command, like MODE. Note that several commands may
be given on the command line, separated by commas.
* Kermit-MS Commands
Kermit-MS V2.26 has the following commands:
BYE to remote server.
CLOSE log file and stop logging remote session.
CONNECT as terminal to remote system.
DEFINE macros of Kermit-MS commands.
DELETE local files.
DIRECTORY listing of local files.
DO a macro expansion.
EXIT from Kermit-MS.
FINISH Shut down remote server.
GET remote files from server.
HELP about Kermit-MS.
LOCAL prefix for local file management commands.
LOG remote terminal session.
LOGOUT remote server.
PUSH to MS-DOS command level.
QUIT from Kermit-MS
RECEIVE files from remote Kermit.
REMOTE prefix for remote file management commands.
RUN an MS-DOS program.
SEND files to remote Kermit.
SERVER mode of remote operation.
SET various parameters.
SHOW various parameters.
SPACE inquiry.
STATUS inquiry.
TAKE commands from file.
The following SET commands are available in Kermit-MS:
BAUD Communications port line speed
BELL Whether to beep at the end of a transaction
BLOCK-CHECK-TYPE Level of error checking for file transfer
DEBUG Display packet contents during file transfer
DEFAULT-DISK Default disk drive for file i/o
DESTINATION Default destination device for incoming files
END-OF-LINE Packet terminator
EOF Method for determining or marking end of file
ESCAPE Escape character for CONNECT
FLOW-CONTROL Enable or disable XON/XOFF
HANDSHAKE Half-duplex line turnaround option
HEATH19 Heath/Zenith-19 terminal emulation
INCOMPLETE What to do with an incompletely received file
KEY Specify key redefinitions, or "keystroke macros"
LOCAL-ECHO Specify which host does the echoing during CONNECT
PARITY Character parity to use
PORT Select a communications port
PROMPT Change the "Kermit-MS>" prompt to something else
RECEIVE Request remote Kermit to use specified parameters
REMOTE For running Kermit-MS interactively from back port
SEND Use the specified parameters during file transfer
TAKE-ECHO Control echoing of commands from TAKE files
TIMER Enable/disable timeouts during file transfer
WARNING Specify how to handle filename collisions
The STATUS command shows the values of parameters which may be SET.
* Command Macros
Kermit-MS provides a facility for combining commands into "macros."
Command macro definitions may be included in your MSKERMIT.INI file,
TAKEn explicitly from a specified file, or typed interactively, and may
be invoked with the DO command.
* Command Macros
Kermit-MS command macros are constructed with the DEFINE command. The
syntax is
DEFINE macro-name [command [, command [, ...]]]
Any Kermit-MS commands may be included. Example:
define telenet set parity mark, set baud 1200, connect
A Kermit-MS command macro is invoked using the DO command. For in-
stance, Kermit-MS comes with a predefined macro to allow convenient
setup for IBM communications; to invoke it, you would type
do ibm
The IBM macro is defined as "parity mark, handshake xon, local-echo on,
timer on". You can delete or replace this definition by adding a new
(perhaps null) definition, such as
define ibm parity even, handshake cr, local-echo on, timer on]
or
define ibm
Command macro definitions can be displayed with the SHOW MACROS command.
* Terminal Emulation
Here are the terminal emulation options for the systems presently sup-
ported by Kermit-MS:
System EscChar Cabilities Terminal Service
IBM PC, XT ^] R M P K Heath19 emulation
DEC Rainbow ^] R P K VT102 firmware
HP-150 ^] R HP-2623 firmware
Wang PC ^A Wang firmware
Generic DOS ^] Depends on system
Under Capabilities, R means rollback, M means mode line, P means printer
control, and K means key redefinition.
IBM PC/XT Kermit can disable Heath-19 emulation and use an external con-
sole device driver like ANSI.SYS instead.
The escape character is used to regain the attention of Kermit-MS. When
you type the escape character, Kermit-MS waits for you to follow it with
a single character command:
? Help -- prints the available single-character commands.
C Close the connection and return to Kermit-MS prompt level.
S Show the status of the connection.
B Send a BREAK signal to the port.
0 (the digit zero) Send a NUL (ASCII 0) to the port.
Q Temporarily quit logging the remote session.
R Resume logging the remote session.
M Toggle the mode line, i.e. turn it off if it is on & vice versa.
^] (or whatever you have set the escape character to be)
Typing the escape character twice sends one copy of it to the con-
nected host.
Typing any other character (except the space bar, which is the "null
command") after the escape character will cause Kermit-MS to beep, but
will do no harm. The escape character can be changed to something other
than Control-Rightbracket by using the SET ESCAPE command.
Kermit-MS includes several advanced features for use during terminal
emulation, including screen scroll, printer control, and key redefini-
tions.
X. Screen Scroll
Kermit-MS provides several pages of screen memory, which may be scrolled
up and down using keys as follows:
Function IBM PC/XT Rainbow HP-150
Screen Down PgDn PrevScreen Prev
Line Down Ctrl-PgDn Ctrl-PrevScreen Shift-UpArrow
Screen Up PgUp NextScreen Next
Line Up Ctrl-PgUp Ctrl-NextScreen Shift-DownArrow
Top of Memory Home
Bottom of Memory End
X. Printer Control
A locally attached printer may be controlled in the normal manner, on
most systems. Pushing the "Print Screen" key (shifted on some systems)
will cause the current contents of the screen to be printed or spooled;
holding down CTRL while depressing Print Screen will start or stop the
spooling of incoming characters to the printer.
CTRL-Print-Screen can be simulated with the Kermit-MS LOG PRN and CLOSE
commands.
X. Key Redefinitions
Use SHOW KEY to find out the scan code of the key you want to redefine,
then use SET KEY SCAN xxx to define the new value. Control characters
are entered in the definition string as \ooo (a backslash followed by 2
or 3 octal digits denoting the ASCII value of the character).
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mskermit.hlp
/bin/echo -n ' '; /bin/ls -ld mskermit.hlp
fi
/bin/echo 'Extracting msmkboo.c'
sed 's/^X//' <<'//go.sysin dd *' >msmkboo.c
X/* MSNKBOO.C
*
* This program takes a file and encodes it into printable characters.
* These printable files can then be decoded by the programs MSPCBOOT.BAS
* or MSPCTRAN.BAS as the need may be. The file is encoded by taking
* three consecutive eight bit bytes and dividing them into four six bit
* bytes. An ASCII zero was then added to the resulting four characters.
* to make them all printable ASCII characters in the range of the
* character zero to the character underscore. In order to reduce the
* size of the file null repeat count was used. The null repeat count
* compresses up to 78 consecutive nulls into only two characters. This
* is done by using the character tilde (~) as an indication that a group
* of repetitive nulls has occured. The character following the tilde is
* number of nulls in the group. The number is also converted in to a
* printable character by adding an ASCII zero. The highest number of
* nulls is therefore the highest printable character tilde. This is
* equal to tilde minus zero nulls or 78 nulls. Because of the three
* byte to four byte encoding the repeat counting can only start with
* the first character of a three byte triplet.
*
* This C program was written specifically for the DEC-20 and as such
* will not easily be transported to another system. The main problem
* lies in the file I/O routines. It is necessary to make sure that
* untranslated eight bit bytes are input from the input file. The
* main change would be to make the OPEN statement reflect this for
* your particular system and brand of UNIX and C. The rest of the
* program should be transportable with little or no problems.
*
*/
#include <stdio.h> /* Standard UNIX i/o definitions */
#include <file.h>
X/* Symbol Definitions */
#define MAXPACK 80 /* Maximum packet size */
#define MYRPTQ '~' /* Repeat count prefix I will use */
#define DATALEN 78 /* Length of data buffer */
#define TRUE -1 /* Boolean constants */
#define FALSE 0
X/* Macros */
#define tochar(ch) ((ch) + '0')
X/* Global Variables */
int size, /* Size of present data */
maxsize, /* Max size for data field */
nc, /* Number of input chars */
oc, /* Number of output chars */
fd, /* File pointer of file to read/write */
ofd,
rpt, /* repeat count */
rptq, /* repeat quote */
rptflg, /* repeat processing flag */
eoflag, /* Set when file is empty. */
otot; /* What char number we are processing. */
char t, /* Current character */
one,
two,
three,
*filnam, /* Current file name */
*ofile,
packet[MAXPACK]; /* Packet buffer */
main(argc,argv) /* Main program */
int argc; /* Command line argument count */
char **argv; /* Pointers to args */
{
char sfile(); /* Send file routine & ret code */
if (--argc != 2) usage(); /* Make sure there's a command line. */
rptq = MYRPTQ; /* Repeat Quote */
rptflg = TRUE; /* Repeat Count Processing Flag */
filnam = *++argv; /* Get file to send */
ofile = *++argv; /* Output file to create */
sfile();
printf("Done, in: %d, out: %d, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
}
X/*
S F I L E - Send a whole file
*/
char sfile() /* Send a file */
{
char *i;
fd = open(filnam,FATT_RDONLY|FATT_BINARY|FATT_DEFSIZE);
if (fd < 0) /* Report any errors */
{
printf("\n?Error opening file \"%s\"\n",filnam);
exit(1);
}
ofd = open(ofile,FATT_WRONLY|FATT_CREATE|FATT_BINARY);
if (ofd < 0)
{
printf("\n?error opening file \"%s\"\n",ofile);
exit(1);
}
oc = strlen(filnam); /* Get the string length. */
for (i=filnam; *i != '\0'; i++) /* Uppercase the file name. */
if (*i >= 'a' && *i <= 'z') *i ^= 040;
write(ofd,filnam,oc); /* Write the file name in the file. */
write(ofd,"\r\n",2);
maxsize = DATALEN - 5;
rpt = 0; /* Zero the repeat count. */
oc = nc = 0; /* Output & input character counts. */
otot = 1; /* Start with first char of triplet. */
while (getbuf() > 0) /* While not EOF, get a packet. */
{
while (size < DATALEN - 1) packet[size++] = ' ';
packet[size++] = '\r'; /* Explicit CRLF. */
packet[size++] = '\n';
packet[size] = '\0';
oc += size; /* Count output size. */
write(ofd,packet,size); /* Write the packet to the file. */
printf("%d: %s",size,packet); /* Print on the screen for testing. */
}
}
X/*
G E T B U F -- Do one packet.
*/
getbuf() /* Fill one packet buffer. */
{
if (eoflag != 0) return(-1); /* If at the end of file, stop. */
size = 0;
while((t = getch()) >= 0) /* t == -1 means EOF. */
{
nc++; /* Count the character. */
process(t); /* Process the character. */
if (size >= maxsize) /* If the packet is full, */
{
packet[size] = '\0'; /* terminate the string. */
return(size);
}
}
eoflag = -1; /* Say we hit the end of the file. */
process(0); /* Clean out any remaining chars. */
process(0);
process(' ');
packet[size] = '\0'; /* Return any partial final buffer. */
return(size);
}
X/* P R O C E S S -- Do one character. */
process(a)
char a;
{
if (otot == 1) /* Is this the first of three chars? */
{
if (a == 0) /* Is it a null? */
{
if (++rpt < 78) /* Below max nulls, just count. */
return;
else if (rpt == 78) /* Reached max number, must output. */
{
packet[size++] = rptq; /* Put in null repeat char and */
packet[size++] = tochar(rpt); /* number of nulls. */
packet[size] = '\0';
rpt = 0;
return;
}
}
else
{
if (rpt == 1) /* Just one null? */
{
one = 0; /* Say the first char was a null. */
two = a; /* This char is the second one. */
otot = 3; /* Look for the third char. */
rpt = 0; /* Restart null count. */
return;
}
if (rpt > 1) /* Some number of nulls? */
{
packet[size++] = rptq; /* Insert the repeat prefix */
packet[size++] = tochar(rpt); /* and count. */
packet[size] = '\0';
rpt = 0; /* Reset repeat counter. */
}
one = a; /* Set first character. */
otot = 2; /* Say we are at the second char. */
}
}
else if (otot == 2)
{
two = a; /* Set second character. */
otot = 3; /* Say we are at the third char. */
}
else
{
three = a;
otot = 1; /* Start over at one. */
pack(one,two,three); /* Pack in the three characters. */
}
}
X/* This routine does the actual three character to four character encoding.
* The concept is relatively straight forward. The first output character
* consists of the first (high order or most significant) six bits of the
* first input character. The second output character is made from the
* remaining two low order bits of the first input character and the first
* four high order bits of the second input character. The third output
* character is built from the last four low order bits of the second input
* character and the two high order bits of the third input character. The
* fourth and last output character consists of the six low order bit of
* the third input character. In this way the three eight bit input char-
* acters (for a total of 24 bits) are divided into four six bit output
* characters (also for a total of 24 bits). In order to make the four
* output characters printable an ASCII zero is then added to each of them.
*
*/
pack(x,y,z)
char x,y,z;
{
packet[size++] = tochar((x >> 2) & 077);
packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
packet[size++] = tochar(z & 077);
packet[size] = '\0';
}
getch() /* Get next (or pushed) char. */
{
char a;
return((read(fd,&a,1) > 0) ? a : -1); /* (or -1 if EOF) */
}
usage() /* Give message if user makes */
{ /* a mistake in the command. */
fprintf(stderr,"usage: msmkboo inputfile outputfile\n");
exit(1);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msmkboo.c
/bin/echo -n ' '; /bin/ls -ld msmkboo.c
fi
/bin/echo 'Extracting mspctran.bas'
sed 's/^X//' <<'//go.sysin dd *' >mspctran.bas
1 'Use this BASIC program on the PC if you have the printable file
2 'MSKERMIT.BOO already on the PC to convert it to an executable
3 'file. This program takes about 30 minutes to run on a PC with
4 'floppy disks.
5 ' Bill Catchings, June 1984
6 ' Columbia University Center for Computing Activities
10 t$ = time$ ' Save the time.
20 defint a-z ' Integer to gain some speed.
30 n$ = chr$(0)
40 z = asc("0")
50 t = asc("~")-z
60 def fnuchr%(a$)=asc(a$)-z
70 open "MSKERMIT.BOO" for input as #1
100 input#1,f$ ' Is this the right file?
110 if len(f$) > 20 then goto 900
120 open f$ for output as #2
130 print "Outputting to "+f$
200 if eof(1) then goto 800 ' Exit nicely on end of file.
210 input#1,x$ ' Get a line.
220 y$ = "" ' Clear the output buffer.
230 goto 400
300 print#2,y$; ' Print output buffer to file.
310 goto 200 ' Get another line.
400 if len(x$) < 4 goto 300 ' Is the input buffer empty?
410 a = fnuchr%(x$)
420 if a = t then goto 700 ' Null repeat character?
430 q$=mid$(x$,2,3) ' Get the quadruplet to decode.
440 x$=mid$(x$,5)
450 b = fnuchr%(q$)
460 q$ = mid$(q$,2)
470 c = fnuchr%(q$)
480 q$ = mid$(q$,2)
490 d = fnuchr%(q$)
500 y$ = y$ + chr$(((a * 4) + (b \ 16)) and 255) ' Decode the quad.
510 y$ = y$ + chr$(((b * 16) + (c \ 4)) and 255)
520 y$ = y$ + chr$(((c * 64) + d) and 255)
530 goto 400 ' Get another quad.
700 x$ = mid$(x$,2) ' Expand the nulls.
710 r = fnuchr%(x$) ' Get the number of nulls.
715 print " Null: ",r
720 x$ = mid$(x$,2)
730 for i=1 to r ' Loop, adding nulls to string.
740 y$ = y$ + n$
750 next
760 print#2,y$; ' Output the nulls to the file.
770 y$ = "" ' Clear the output buffer.
780 goto 400
800 print "Processing complete, elapsed time: "+t$+" to "+time$
810 print "Output in "+f$
820 close #1,#2
830 goto 9999
900 print "?The version of the MSKERMIT.BOO file is incorrect"
910 goto 820
9999 end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mspctran.bas
/bin/echo -n ' '; /bin/ls -ld mspctran.bas
fi
/bin/echo 'Extracting msrbboo.bas'
sed 's/^X//' <<'//go.sysin dd *' >msrbboo.bas
1 DEFINT A-Z:ZRUBOUT$=CHR$(8)+" "+CHR$(8):ZESCAPE$=CHR$(27):'Sreen utility definitions B.E.
2 ZLEADIN$=ZESCAPE$+"[":ZCLEAR$=ZLEADIN$+"J":ZHOME$=ZLEADIN$+"0;0H"
3 ZDOUBLE1$=ZESCAPE$+"#3":ZDOUBLE2$=ZESCAPE$+"#4":WIDTH 255
4 ZBOLD$=ZLEADIN$+"1m":ZBLINK$=ZLEADIN$+"5m":ZSAVE$=ZESCAPE$+"7"
5 ZREVERSE$=ZLEADIN$+"7m":ZOFF$=ZLEADIN$+"0m":ZREST$=ZESCAPE$+"8"
6 ZGRAPHON$=ZESCAPE$+"(0":ZGRAPHOFF$=ZESCAPE$+"(B":ZBACKER$=ZLEADIN$+"0K"
7 ZKEYPAD$=ZESCAPE$+"=":ZBELL$=CHR$(7):ZCLRLIN$=ZLEADIN$+"2K"
8 DEF FNXY$(ZX,ZY)=ZLEADIN$+MID$(STR$(INT(ZX)),2)+";"+MID$(STR$(INT(ZY)),2)+"H":'Cursor Adressing function (ZX=Line[1..24],ZY=Column[1..80])
9 GOTO 25:'This to be modified to GOTO Start of program <===================
10 ZSTRING$="":ZORGL=ZLENGTH:PRINT ZSAVE$+ZREVERSE$+STRING$(ZORGL,95)+ZOFF$+STRING$(ZORGL,8);:'General Input-GOSUB (Input:ZLENGTH, OUTPUT:ZLENGTH,ZSTRING,ZNUMBER,ZRANDOM)
11 ZTEMP$=INKEY$:ZRANDOM=(ZRANDOM MOD 2000)+1:IF LEN(ZTEMP$)=0 THEN 11'Wait for Char
12 IF ASC(ZTEMP$)=127 OR ASC(ZTEMP$)=8 THEN 17 ELSE IF ASC(ZTEMP$)=21 THEN PRINT ZREST$+ZBACKER$;:ZLENGTH=ZORGL:GOTO 10 ELSE PRINT ZTEMP$;'RUBOUT
13 IF ASC(ZTEMP$)=3 THEN GOTO 9999 ELSE IF ZTEMP$ >= "a" THEN ZTEMP$=CHR$(ASC(ZTEMP$)-32)'Uppercase Modify GOTO xx to Control-C intercept <=====================
14 IF ASC(ZTEMP$)=13 THEN PRINT:GOTO 16'RETURN finishes
15 ZSTRING$=ZSTRING$+ZTEMP$:ZLENGTH=ZLENGTH-1:IF ZLENGTH >0 THEN 11
16 ZLENGTH=LEN(ZSTRING$):ZNUMBER=VAL(ZSTRING$): RETURN
17 IF LEN(ZSTRING$)>0 THEN ZLENGTH=ZLENGTH +1:ZSTRING$=LEFT$(ZSTRING$,(LEN(ZSTRING$)-1)):PRINT ZRUBOUT$;:GOTO 11 ELSE PRINT ZBELL$;: GOTO 11'Cleanup after RUBOUT
18 'End of VT100 definitions *****
19 'Use this BASIC program on the CP/M side of the Rainbow (with
20 'Microsoft MBasic-86) to translate the MSRB100.BOO file on
21 'your CP/M disk to binary .EXE format, then from the MS-DOS
22 'side use RDCPM to transfer the result to the MS-DOS file
23 'system. This program takes about 30 minutes to run on a Rainbow
24 'with floppy disks.
25 '- Bill Catchings, CU; modified for Rainbow by Bernie Eiben, DEC.
26 PRINT ZHOME$+ZCLEAR$;"Rainbow 4for3 Code Expander Version 1"
30 PRINT:PRINT: N$ = CHR$(0)
40 Z = ASC("0")
50 T = ASC("~")-Z
60 DEF FNUCHR%(A$)=ASC(A$)-Z
61 PRINT "FILE-NAME to Expand : ";:ZLENGTH=13:GOSUB 10:'Get Input
70 OPEN "I",1,ZSTRING$
100 INPUT#1,F$ ' Is this the right file?
110 IF LEN(F$) > 20 THEN GOTO 900
120 OPEN "O",2,F$ ' Ouput-name from file
130 PRINT "Outputting to "+F$
200 IF EOF(1) THEN GOTO 800 ' Exit nicely on end of file.
210 INPUT#1,X$ ' Get a line.
220 Y$ = "" ' Clear the output buffer.
230 GOTO 400
300 PRINT#2,Y$; ' Print output buffer to file.
310 GOTO 200 ' Get another line.
400 IF LEN(X$) < 4 GOTO 300 ' Is the input buffer empty?
410 A = FNUCHR%(X$)
420 IF A = T THEN GOTO 700 ' Null repeat character?
430 Q$=MID$(X$,2,3) ' Get the quadruplet to decode.
440 X$=MID$(X$,5)
450 B = FNUCHR%(Q$)
460 Q$ = MID$(Q$,2)
470 C = FNUCHR%(Q$)
480 Q$ = MID$(Q$,2)
490 D = FNUCHR%(Q$)
500 Y$ = Y$ + CHR$(((A * 4) + (B \ 16)) AND 255) ' Decode the quad.
510 Y$ = Y$ + CHR$(((B * 16) + (C \ 4)) AND 255)
520 Y$ = Y$ + CHR$(((C * 64) + D) AND 255)
530 GOTO 400 ' Get another quad.
700 X$ = MID$(X$,2) ' Expand the nulls.
710 R = FNUCHR%(X$) ' Get the number of nulls.
715 PRINT FNXY$(6,5)+ZCLRLIN$;" Null: ",R
720 X$ = MID$(X$,2)
730 FOR I=1 TO R ' Loop, adding nulls to string.
740 Y$ = Y$ + N$
750 NEXT
760 PRINT#2,Y$; ' Output the nulls to the file.
770 Y$ = "" ' Clear the output buffer.
780 GOTO 400
800 PRINT "Processing complete"
810 PRINT "Output in "+F$
820 CLOSE #1,#2
830 GOTO 9999
900 PRINT "?The FORMAT of the ",ZSTRING$," file is incorrect"
910 GOTO 820
9999 END
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbboo.bas
/bin/echo -n ' '; /bin/ls -ld msrbboo.bas
fi
/bin/echo 'Extracting msrbboo.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msrbboo.hlp
Date: Thu 13 Sep 84 16:32:44-EDT
From: Frank da Cruz <SY.FDC at CU20B.ARPA>
Subject: Rainbow MS-DOS Kermit Bootstrapping
To: Info-Kermit at CU20B
Users of DEC Rainbow 100s have complained that there's no bootstrapping
procedure they can use for getting the new MS-DOS Kermit onto the Rainbow
over the communication line. The problem was that Basic was not available
for MS-DOS on the Rainbow (or else it was so new that no one had it yet),
so the Microsoft Basic program we provided for decoding the .BOO (4-for-3
encoded) binary file could not be used on the Rainbow.
Now, thanks to Bernie Eiben at DEC, we have a version of the Basic program
that will run on the CP/M-86 side of the Rainbow. It's a reworking of
MSPCTRAN.BAS, which assumes that you already have the .BOO file on your
CP/M disk. It builds an .EXE file, which you can then move to the MS-DOS
side of your Rainbow by booting MS-DOS and then using RDCPM to get the
file from the CP/M-format disk. How you get the .BOO file onto the CP/M
disk in the first place is another question. Either you use some file
capture utility -- commercial or otherwise -- or else you go through the
DDT bootstrap procedure given for CP/M-80 Kermit (since the Rainbow is
also a CP/M-80 system).
Bernie's program is in KER:MSRBBOO.BAS.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbboo.hlp
/bin/echo -n ' '; /bin/ls -ld msrbboo.hlp
fi
/bin/echo 'Extracting msrbemacs.ini'
sed 's/^X//' <<'//go.sysin dd *' >msrbemacs.ini
; EMACS function key setup for Kermit-MS/Rainbow
;
; C-@ (set mark) on SELECT
set key select
\00
;
; M-h (select region) on CTRL-SELECT
set key scan 1313
\33h
;
; C-U 12 C-X C-I (rigidly indent region 12 spaces) on TAB
set key scan 9
\25\61\62\30\11
; C-X C-I (rigidly indent region) on SHIFT-TAB
set key scan 521
\30\11
;
; C-S (forward search) on FIND
set key find
\23
;
; C-R (reverse search) on CTRL-FIND
set key scan 1307
\22
;
; M-D (delete word) on REMOVE
set key remove
\33d
;
; M-K (delete sentence) on CTRL-REMOVE
set key scan 1311
\33k
;
; C-P (up line) on uparrow
set key scan 295
\20
;
; M-[ (up paragraph) on CTRL-uparrow
set key scan 1319
\33[
;
; C-X [ (up page) on SHIFT-uparrow
set key scan 807
\30[
;
; M-< (top of file) on CTRL-SHIFT-uparrow
set key scan 1831
\33<
;
; C-B (back character) on leftarrow
set key scan 301
\02
;
; C-A (beginning of line) on CTRL-leftarrow
set key scan 1325
\01
;
; M-A (back sentence) on SHIFT-leftarrow
set key scan 813
\33a
;
; C-N (next line) on downarrow
set key scan 297
\16
; M-] (down paragraph) on CTRL-downarrow
set key scan 1321
\33]
;
; C-X ] (down page) on SHIFT-downarrow
set key scan 809
\30]
;
; M-> (end of file) on CTRL-SHIFT-downarrow
set key scan 1833
\30>
;
; C-F (forward character) on rightarrow
set key scan 299
\06
;
; C-E (end of line) on CTRL-rightarrow
set key scan 1323
\05
;
; M-E (end of sentence) on SHIFT-rightarrow
set key scan 811
\33e
;
; C-X E (do keyboard macro) on DO
set key scan 257
\30e
;
; C-U C-X E (do keyboard macro 4x) on CTRL-DO
set key scan 1281
\25\30e
;
; C-U 8 C-X E (do keyboard macro 8x) on SHIFT-DO
set key scan 769
\25\70\30e
;
; C-U C-U C-X E (do keyboard macro 16x) on CTRL-SHIFT-DO
set key scan 1793
\25\25\30e
;
; ^_ on HELP
set key scan 256
\37
;
; C-X C-Z on EXIT
set key scan 271
\30\32
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbemacs.ini
/bin/echo -n ' '; /bin/ls -ld msrbemacs.ini
fi
/bin/echo 'Extracting msxapc.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxapc.asm
; Kermit system dependent module for NEC Advanced Personal Computer (APC)
; Ron Blanford, University of Washington, August 1984
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
false equ 0
true equ 1
; port assignments for 8251 serial controllers
; Standard interface
mndata equ 30H ; Data port (read/write)
mnst1a equ 32H ; Status port (when read)
mncmda equ 32H ; Command port (when written)
mnst2a equ 34H ; Alternate status port (when read)
mnmska equ 34H ; Mask port (when written)
mntdca equ 36H ; Transmit disable port (write only)
; Optional (H14) interface
mndatb equ 31H ; Data port (read/write)
mnst1b equ 33H ; Status port (when read)
mncmdb equ 33H ; Command port (when written)
mnst2b equ 35H ; Alternate status port (when read)
mnmskb equ 35H ; Mask port (when written)
mntdcb equ 37H ; Transmit disable port (write only)
; Status bits from mnst1
txrdy equ 01H ; Bit for output ready.
rxrdy equ 02H ; Bit for input ready.
; Command values for mncmd
ccmd equ 37H ; RTS & DTR high, RX & TX enabled, reset ERR
cbrk equ 08H ; break enabled
cmode equ 40H ; enable mode reset
mmode equ 4EH ; 16x rate, 8 data, no parity, 1 stop
; Mask values for mnmsk
txmsk equ 01H ; disables transmit ready interrupt
rxmsk equ 02H ; disables receive ready interrupt
tbemsk equ 04H ; disables transmit buffer empty interrupt
; port assignments for 8253 timers
; Standard interface
tmdata equ 2BH ; data port
tmcmda equ 27H ; command port
; Optional (H14) interface
tmdatb equ 61H ; data port
tmcmdb equ 67H ; command port
; values for tmcmd which select timer channel and mode
tmsela equ 76H ; Channel 1, mode 3 (standard port)
tmselb equ 36H ; Channel 0, mode 3 (optional port)
; Timer information for current port selection
tmrinfo struc
tmdat dw 0 ; data port
tmcmd dw 0 ; command port
tmsel db 0 ; byte which selects channel and mode
tmrinfo ends
; port assignments for 8259 interrupt controllers
; Standard interface
intcmda equ 20H ; Command port (master controller)
intmska equ 22H ; Mask port
ictmsk equ 08H ; Timer interrupt mask (to master)
icsmska equ 02H ; Standard serial interrupt mask (to master)
icsvcta equ 11H ; Interrupt vector for standard interface
; Optional (H14) interface
; The interrupt request vector for the optional (H14) serial interface is
; jumper-selectable to any of vectors IR2, IR5, IR8, or IR12. NEC recommends
; that IR8 be used, so that has been selected as the default here. To use
; any of the other vectors, set the following conditionals appropriately.
; Only one of the following should be true:
IR2 equ false ; interrupt vector 2
IR5 equ false ; interrupt vector 5
IR8 equ true ; interrupt vector 8
IR12 equ false ; interrupt vector 12
IF IR2
intcmdb equ 20H ; Command port (master controller)
intmskb equ 22H ; Mask port
icsmskb equ 04H ; Interrupt mask
icsvctb equ 12H ; Interrupt table index
ENDIF
IF IR5
intcmdb equ 20H ; Command port (master controller)
intmskb equ 22H ; Mask port
icsmskb equ 20H ; Interrupt mask
icsvctb equ 15H ; Interrupt table index
ENDIF
IF IR8
intcmdb equ 28H ; Command port (slave controller)
intmskb equ 2AH ; Mask port
icsmskb equ 02H ; Interrupt mask
icsvctb equ 19H ; Interrupt table index
ENDIF
IF IR12
intcmdb equ 28H ; Command port (slave controller)
intmskb equ 2AH ; Mask port
icsmskb equ 20H ; Interrupt mask
icsvctb equ 1DH ; Interrupt table index
ENDIF
; generic end of interrupt for intcmd
icEOI equ 20H
; miscellaneous constants
ctrlP equ 10H ; Key that toggles printer echo
mntrgh equ bufsiz*3/4 ; High XON/XOFF trigger = 3/4 of buffer full.
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'NEC APC$'
nyimsg db cr,lf,'Not yet implemented$'
badbd db cr,lf,'Unimplemented baud rate$'
lstpos dw 0 ; column position for printer echoing
crlf db cr,lf,'$'
delstr db BS,' ',BS,'$' ; Delete string.
clrlin db cr,'$' ; Clear line (just the cr part).
ceolseq db esc,'[K$' ; Clear to end of line
cpseq db esc,'=rc' ; rc replaced by row and column before display
clrseq db 01EH,01AH,'$' ; Home cursor and clear screen
; The following color values were selected to look well on both monochrome
; and color monitors. In particular, the normal color should be at normal
; intensity on the monochrome monitor (green, blue, or cyan), and the bold
; color should be at bold intensity (red, purple, yellow, or white).
nrmseq db esc,'[0m$' ; reset to normal video (green)
invseq db esc,'[7m$' ; start reverse video (green)
bldseq db esc,'[19m$' ; start bold video (purple)
ourarg termarg <>
modem mdminfo <mndata,mnst1a,mncmda,0,0,0,0>
timer tmrinfo <tmdata,tmcmda,tmsela>
ourflgs db 0 ; flags for telnet options
fprint equ 80H ; echo screen output to printer
oldsera dw ? ; old serial handler for standard port
oldsega dw ? ; segment of above
oldmska db ? ; old interrupt controller mask
portina db 0 ; Has comm port been initialized.
oldserb dw ? ; old serial handler for optional port
oldsegb dw ? ; segment of same.
oldmskb db ? ; old interrupt controller mask
portinb db 0 ; Has comm port been initialized.
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
; variables for serial interrupt handler
source db bufsiz DUP (?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
savesi dw 0 ; Save SI register here.
dw 80 DUP (?) ; local stack for interrupt processing
mnstk dw ?
mnsp dw ? ; remote stack info
mnsseg dw ?
shkbuf db 300 dup (?) ; room to display key definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
setktab db 2
mkeyw 'BACKSPACE',08H
mkeyw 'SCAN',-1
setkhlp db cr,lf,'BACKSPACE, or SCAN followed by decimal ASCII code$'
comptab db 7
mkeyw '1',1
mkeyw '2',0
mkeyw 'COM1',1
mkeyw 'COM2',0
mkeyw 'H14',0
mkeyw 'OPTIONAL',0
mkeyw 'STANDARD',1
bddat label word
dw 0D30H ; 45.5 baud
dw 0C00H ; 50 baud
dw 0800H ; 75 baud
dw 0574H ; 110 baud
dw 0476H ; 134.5 baud
dw 0400H ; 150 baud
dw 0200H ; 300 baud
dw 0100H ; 600 baud
dw 0080H ; 1200 baud
dw 0055H ; 1800 baud
dw 004DH ; 2000 baud
dw 0040H ; 2400 baud
dw 0020H ; 4800 baud
dw 0010H ; 9600 baud
dw 0008H ; 19200 baud
dw 0004H ; 38400 baud (not tested - may not work)
datas ends
code segment public
extrn comnd:near, dopar:near
assume cs:code,ds:datas
; local initialization routine, called by Kermit initialization.
LCLINI PROC NEAR
cld
mov flags.vtflg,0 ; turn off heath emulation
mov dx,offset nrmseq ; set to our normal background color
call tmsg
ret
LCLINI ENDP
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. The only problem is that a value of two
; is returned for single drive systems to be consistent
; with the idea of the system having logical drives A and
; B. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; current disk value to AL.
int dos
mov dl,al ; put current disk in DL.
mov ah,seldsk ; select current disk.
int dos ; get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
; On the APC there is no direct access to the keyboard; the best we
; can do is use direct console I/O to get a key value which has already
; been translated to some extent by the operating system.
SHOWKEY PROC NEAR
push es
push ax ; save the terminal argument block
mov bx,ds
mov es,bx ; address data segment
cld
showk1: mov ah,dconio ; get scan value
mov dx,0FFH
int dos
jz showk1
mov ah,0
push ax ; save scan code
mov di,offset shkbuf ; move 'Scan code' message to buffer
mov si,offset shkmsg
mov cx,shkmln
rep movsb
call nout ; add scan code to buffer
mov si,offset shkms1 ; move 'Definition' message to buffer
mov cx,shkm1ln
rep movsb
pop ax ; retrieve scan code
pop bx ; and terminal argument block
mov cx,[bx].klen ; length of translation table
jcxz showk3 ; no table, key not defined
push di
mov di,[bx].ktab ; get table address
repne scasw ; look for scan code
mov si,di
pop di
jne showk3 ; not defined
sub si,[bx].ktab ; compute entry offset in table
sub si,2
add si,[bx].krpl ; index to replacement
mov si,[si] ; get its address
mov cl,[si] ; get its length
mov ch,0
inc si
rep movsb ; transfer replacement to display buffer
showk3: mov ax,offset shkbuf ; return address of buffer in ax
mov cx,di ; and length in cx
sub cx,ax
pop es
ret
SHOWKEY ENDP
; copy numeric value from AX to ASCII buffer indicated by DI. DI is updated.
NOUT PROC NEAR
mov dx,0 ; zero high word
mov bx,10 ; divide
div bx
push dx ; save remainder digit
or ax,ax ; anything left?
jz nout1 ; no, start output phase
call nout
nout1: pop ax ; retrieve a digit
add al,'0' ; make it ASCII
stosb ; put it in buffer
ret
NOUT ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we have to xon the host.
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: pushf ; save current interrupt value
cli ; disable interrupts while manipulating pointers
mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
popf ; restore original interrupt flag
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
CHKXON PROC NEAR
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop ; ignore failure
nop
nop
mov xofsnt,false ; remember we've sent an xon.
chkxo1: pop bx ; restore register
ret ; and return
CHKXON ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
OUTCHR PROC NEAR
mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
sub cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,modem.mdstat ; port status register
outch3: in al,dx
test al,txrdy ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
OUTCHR ENDP
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
mov dx,modem.mdcom ; send to command port
mov al,cbrk+ccmd ; add break to normal command
out dx,al
sub cx,cx ; wait a while
sndbr1: loop sndbr1
mov al,ccmd ; restore normal command
out dx,al
ret ; and return.
SENDBR ENDP
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
pushf ; save current interrupt value
cli ; disable interrupts
mov ax,offset source ; reset pointers to beginning of buffer
mov srcpnt,ax
mov savesi,ax
mov count,0
popf ; restore original interrupt value
ret
CLRBUF ENDP
; Set the baud rate for the current port, based on the value in the
; portinfo structure. On entry, previous value of baud rate is saved in AX.
; Returns normally.
DOBAUD PROC NEAR
mov bp,portval
mov bx,ds:[bp].baud ;make sure new value is valid
shl bx,1
add bx,offset bddat
cmp word ptr [bx],0FFH
jne dobd0
mov ds:[bp].baud,ax ;replace bad rate with previous value
mov dx,offset badbd
jmp tmsg
dobd0: mov dx,timer.tmcmd ;timer command port
mov al,timer.tmsel ;select proper channel and mode
out dx,al
mov ax,[bx] ;get timer initializer for this rate
mov dx,timer.tmdat ;timer data port
out dx,al ;output low byte
mov al,ah
out dx,al ;output high byte
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
mov bx,portval ; no way to determine baud rate on APC
mov [bx].baud,B1200 ; so set default baud rate to 1200
ret
GETBAUD ENDP
; Set the mode for the current port. This is part of the serial
; initialization routine.
DOMODE PROC NEAR
mov dx,modem.mdcom ;send 3 zeros to command port to reset chip
mov al,0
out dx,al
mov al,0
out dx,al
mov al,0
out dx,al
mov al,cmode ;enable mode setting
out dx,al
push ax ;allow 8251 time to reset
pop ax
push ax
pop ax
mov al,mmode ;mode: 16x rate, 8 data, no parity, 1 stop
out dx,al
mov al,ccmd ;RTS & DTR high, RX & TX enabled, reset errors
out dx,al
ret
DOMODE ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset comptab ;get port selection
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm ;get a confirmation
call comnd
jmp comx
nop
pop bx
mov flags.comflg,bl ;save port selection
cmp flags.comflg,1
jne coms2
mov ax,offset port1 ;set to run on port 1
mov portval,ax
call resetb ;reset port 2, if in use
call inita ;set up port 1
ret
coms2: mov ax,offset port2 ;set to run on port 2
mov portval,ax
call reseta ;reset port 1, if in use
call initb ;set up port 2
ret
comx: pop bx
ret
COMS ENDP
; initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.
SERINI PROC NEAR
cmp flags.comflg,1
jne seri2
call resetb
call inita
ret
seri2: call reseta
call initb
ret
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
call reseta ;reset port 1
call resetb ;reset port 2
ret
SERRST ENDP
; Local routine to initialize the standard serial port
INITA PROC NEAR
cmp portina,1 ; Did we initialize port already? [21c]
je inita0 ; Yes, so just leave. [21c]
push es
cli ; Disable interrupts
mov ax,offset port1
mov portval,ax
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*icsvcta] ; save standard port interrupt vector
mov oldsera,ax
mov ax,es:[4*icsvcta+2]
mov oldsega,ax
mov ax,offset serint ; point to our routine
mov es:[4*icsvcta],ax ; point at our serial routine
mov es:[4*icsvcta+2],cs ; our segment
mov dx,intmska ; set up standard port...
in al,dx
mov oldmska,al ; save old master controller mask
; NEC recommends that the timer interrupt be disabled during interrupt-
; driven serial I/O, but this disables the clock display and keyboard
; repeat. I have not had any problems leaving it enabled, so I will
; leave it alone here. If problems develop, uncomment the following
; line to disable timer interrupts. -- RonB
; or al,ictmsk ; disable timer interrupt
and al,not icsmska ; enable serial interrupt at master controller
out dx,al
mov dx,mnmska ; enable serial interrupt at port
mov al,txmsk+tbemsk ; disable tx and tbe interrupts (enable rx)
out dx,al
mov dx,mntdca ; enable operation of serial port
mov al,0
out dx,al
mov modem.mddat,mndata
mov modem.mdstat,mnst1a
mov modem.mdcom,mncmda
mov timer.tmdat,tmdata
mov timer.tmcmd,tmcmda
mov timer.tmsel,tmsela
call domode
call dobaud
mov portina,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
pop es
inita0: ret
INITA ENDP
; Local routine to initialize the optional (H14) serial port
INITB PROC NEAR
cmp portinb,1 ; Did we initialize port already? [21c]
je initb0 ; Yes, so just leave. [21c]
push es
cli ; Disable interrupts
mov ax,offset port2
mov portval,ax
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*icsvctb] ; save optional port interrupt vector
mov oldserb,ax
mov ax,es:[4*icsvctb+2]
mov oldsegb,ax
mov ax,offset serint ; point to our routine
mov es:[4*icsvctb],ax ; point at our serial routine
mov es:[4*icsvctb+2],cs ; our segment
mov dx,intmskb ; set up optional port...
in al,dx
mov oldmskb,al ; save old master or slave controller mask
and al,not icsmskb ; enable serial interrupt at controller
out dx,al
mov dx,mnmskb ; enable serial interrupt at port
mov al,txmsk+tbemsk ; disable tx and tbe interrupts (enable rx)
out dx,al
mov dx,mntdcb ; enable operation of serial port
mov al,0
out dx,al
mov modem.mdstat,mnst1b
mov modem.mddat,mndatb
mov modem.mdcom,mncmdb
mov timer.tmdat,tmdatb
mov timer.tmcmd,tmcmdb
mov timer.tmsel,tmselb
call domode
call dobaud
mov portinb,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
pop es
initb0: ret
INITB ENDP
; Reset standard serial port
RESETA PROC NEAR
cmp portina,0 ; Did we reset port already?
je rsta0 ; Yes, so just leave.
push es
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov ax,oldsera ; Restore interrupt vector
mov es:[4*icsvcta],ax
mov ax,oldsega
mov es:[4*icsvcta+2],ax
mov dx,intmska ; restore old master controller mask
mov al,oldmska
out dx,al
mov dx,mnmska ; disable serial interrupts at port
mov al,txmsk+rxmsk+tbemsk
out dx,al
mov portina,0 ; Remember port has been reset
sti ; Allow interrupts
pop es
rsta0: ret
RESETA ENDP
; Reset optional (H14) serial port
RESETB PROC NEAR
cmp portinb,0 ; Did we reset port already?
je rstb0 ; Yes, so just leave.
push es
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov ax,oldserb ; Restore interrupt vector
mov es:[4*icsvctb],ax
mov ax,oldsegb
mov es:[4*icsvctb+2],ax
mov dx,intmskb ; restore old slave controller mask
mov al,oldmskb
out dx,al
mov dx,mnmskb ; disable serial interrupts at port
mov al,txmsk+rxmsk+tbemsk
out dx,al
mov portinb,0 ; Remember port has been reset
sti ; Allow interrupts
pop es
rstb0: ret
RESETB ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
SERINT PROC NEAR
push ds ; save these on remote stack
push ax
mov ax,seg datas ; get our own data segment
mov ds,ax
mov mnsp,sp ; save remote stack information
mov mnsseg,ss
mov sp,offset mnstk ; switch to local stack
mov ss,ax
push es ; and save remaining registers
push bp
push di
push si
push dx
push cx
push bx
mov es,ax
call mnproc ; process the interrupt
mov al,icEOI
cmp flags.comflg,1 ; If using standard port
je intr1
mov dx,intcmdb ; or H14 vectored to master
cmp dx,intcmda
je intr1 ; only signal End of Interrupt to master,
out dx,al ; otherwise signal to both slave and master.
intr1: mov dx,intcmda
out dx,al
pop bx ; restore registers from stack
pop cx
pop dx
pop si
pop di
pop bp
pop es
mov ax,mnsseg ; switch back to remote stack
mov ss,ax
mov ax,mnsp
mov sp,ax
pop ax
pop ds
iret
; handler for serial input
mnproc: cld
mov di,srcpnt ; get buffer pointer
mov dx,modem.mdstat ; is data available?
in al,dx
test al,rxrdy
jz mnpro7
mov dx,modem.mddat ; read data
in al,dx
or al,al
jz mnpro7 ; Ignore nulls.
cmp al,7FH ; Ignore rubouts, too.
jz mnpro7
mov ah,al
and ah,7fH ; only consider low-order 7 bits for flow ctl.
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je mnpro4 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp ah,bl ; Is it an XOFF?
jne mnpro3 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp short mnpro7
mnpro3: cmp ah,bh ; Get an XON?
jne mnpro4 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp mnpro7
mnpro4: stosb
cmp di,offset source + bufsiz
jb mnpro5 ; not past end...
mov di,offset source ; wrap buffer around
mnpro5: mov srcpnt,di ; update ptr
inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je mnpro7 ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je mnpro7 ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe mnpro7 ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop ; ignore failure.
nop
nop
mov xofsnt,true ; Remember we sent it.
mnpro7: ret
SERINT ENDP
; Dumb terminal emulator. Anyone wishing to enhance it is encouraged
; to do so.
TERM PROC NEAR
mov si,ax ; save argument block locally
mov di,offset ourarg
mov ax,ds
mov es,ax
mov cx,size termarg
rep movsb
term1: call prtchr ; Serial port input processor
jmp short term2 ; ...have a char
nop
jmp termk ; no char, continue
term2: and al,7FH ; only use ASCII in terminal mode
push ax
mov dl,al
mov ah,conout
int dos ; display char
pop ax
test ourarg.flgs,capt ; are we capturing output?
jz term3
push ax
call ourarg.captr
pop ax
term3: test ourflgs,fprint ; are we echoing to printer?
jz termk
call lstchr
termk: mov ah,dconio ; Keyboard input processor
mov dl,0FFH
int dos ; check console
jz term1 ; no char, continue
cmp al,ourarg.escc ; is it the escape char?
je termx
cmp al,ctrlP ; is it the print toggle?
jne term6
xor ourflgs,fprint
jmp term1
term6: call trnout ; translate key and send it out
jmp term1
termx: ret
; do appropriate translations on input key, and transmit
trnout: mov ah,0
test ourarg.flgs,havtt ; is there a translation table?
jz trnou2
mov cx,ourarg.klen ; get table length and origin
mov di,ourarg.ktab
repne scasw ; look for key
jne trnou2 ; if not found, just send it
sub di,ourarg.ktab ; reset to offset of replacement
sub di,2
add di,ourarg.krpl
mov si,[di]
mov cl,[si] ; get length of replacement
mov ch,0
jcxz trnou3 ; if length is zero, send nothing
inc si
trnou1: lodsb ; get replacement character
push si
push cx
call sndhst ; send it to port
pop cx
pop si
loop trnou1 ; continue until translation complete
ret
trnou2: call sndhst ; plain characters go out as they are
trnou3: ret
; send character in AL to port, with possible local echo
sndhst: push ax
mov ah,al
call outchr ; send char to port
nop ; ...don't care if it fails
nop
nop
pop ax
test ourarg.flgs,lclecho ; doing local echo?
jz sndhs2
mov dl,al
mov ah,conout
int dos ; if so, display char
sndhs2: ret
; send character to printer. The only special case is the tab, which must
; be expanded to spaces because MS-DOS doesn't.
lstchr: cmp al,tab
jne lstch2
mov ax,lstpos ; current column position
mov cx,8 ; # of spaces = 8 - (column % 8)
div cl
sub cl,ah
add lstpos,cx ; update the column position
mov al,' '
lstch1: call lstch4 ; print all the spaces
loop lstch1
ret
lstch2: cmp al,cr ; CR returns column count to zero
jne lstch3
mov lstpos,0
lstch3: cmp al,' ' ; only printable characters are counted
jb lstch4
cmp al,del
je lstch4
inc lstpos
lstch4: mov dl,al ; print the character in any case
mov ah,lstout
int dos
ret
TERM ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
VTS ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
push si
cmp dh,25 ; out of range just assumes high value
jb poscu1
mov dh,24
poscu1: cmp dl,80
jb poscu2
mov dl,79
poscu2: add dx,2020H ; add offset for ADM cursor addressing
mov cpseq+2,dh
mov cpseq+3,dl
mov si,offset cpseq ; print sequence (ESC=rc)
mov cx,4
posc1: lodsb
mov dl,al
mov ah,conout
int dos
loop posc1
pop si
ret
POSCUR ENDP
; Locate; homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
cmp al,del ; Del character needs extra backspace
jne dodel1
mov dl,bs
mov ah,conout
int dos
dodel1: mov dx,offset delstr ; Erase weird character.
jmp tmsg
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov dx,offset clrlin ; this just goes to left margin...
call tmsg
jmp clearl ; now clear line
CTLU ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov dx,offset ceolseq ; clear sequence
jmp tmsg
CLEARL ENDP
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov dx,offset clrseq ; clear screen sequence
jmp tmsg
CMBLNK ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
PUTMOD PROC NEAR
push dx ; preserve message
mov dx,24*100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
call tmsg
pop dx ; print the message
call tmsg
mov dx,offset nrmseq ; normal video
jmp tmsg
PUTMOD ENDP
; clear the mode line written by putmod. Returns normally.
CLRMOD PROC NEAR
mov dx,24*100H
call poscur
jmp clearl
CLRMOD ENDP
; Put a help message on the screen. This one uses bold video...
; pass the message in ax, terminated by a null. Returns normally.
PUTHLP PROC NEAR
push ax ; save pointer to message
mov dx,offset crlf
call tmsg
mov dx,offset bldseq ; set to bold video
call tmsg
pop si ; retrieve pointer to message
puth1: lodsb ; get a character
cmp al,0
je puth2 ; stop if terminator
mov dl,al ; otherwise display the character
mov ah,conout
int dos
jmp puth1
puth2: mov dx,offset nrmseq ; reset to normal video
call tmsg
mov dx,offset crlf
call tmsg
ret
PUTHLP ENDP
; Produce a short beep. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; Prints $-terminated message in dx, for local use only
TMSG PROC NEAR
mov ah,prstr
int dos
ret
TMSG ENDP
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxapc.asm
/bin/echo -n ' '; /bin/ls -ld msxapc.asm
fi
/bin/echo 'Extracting msxdmb.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxdmb.asm
code segment public
code ends
datas segment public 'datas'
datas ends
stack segment stack 'stack'
stack ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxdmb.asm
/bin/echo -n ' '; /bin/ls -ld msxdmb.asm
fi
/bin/echo 'Extracting msxdmb.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msxdmb.hlp
MSXDMB.ASM is a dummy file to make the segments come out in the right order
on the Rainbow version of Kermit-MS. It must be included with the other
modules, as the first one.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxdmb.hlp
/bin/echo -n ' '; /bin/ls -ld msxdmb.hlp
fi
/bin/echo 'Extracting msxgen.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxgen.asm
; Generic MS DOS Kermit module
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
public dodisk, getbaud, beep
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
false equ 0
true equ 1
instat equ 6
rddev equ 3fH
open equ 3dH
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'Generic MS-DOS 2.0$'
erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40 db cr,lf,'?Warning: Unrecognized baud rate$'
erms41 db cr,lf,'?Warning: Cannot open com port$'
erms50 db cr,lf,'Error reading from device$'
hnd1 db cr,lf,'Enter a file handle. Check your DOS manual if you are '
db cr,lf,'not certain what value to supply (generally 3).$'
hnd2 db cr,lf,'Handle: $'
hnderr db cr,lf,'Warning: Handle not known. Any routine using the '
db cr,lf,'communications port will probably not work.$'
hndhlp db cr,lf,'A four digit file handle $'
badbd db cr,lf,'Unimplemented baud rate$'
noimp db cr,lf,'Command not implemented.$'
shkmsg db 'Not implemented.'
shklen equ $-shkmsg
setktab db 0
setkhlp db 0
crlf db cr,lf,'$'
delstr db BS,BS,' ',BS,BS,'$' ; Delete string. [21d]
clrlin db cr,'$' ; Clear line (just the cr part).
clreol db '^U',cr,lf,'$' ; Clear line.
telflg db 0 ; non-zero if we're a terminal.
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
count dw 0 ; Number of chars in int buffer.
prthnd dw 0 ; Port handle.
prttab dw com2,com1
com1 db 'COM1',0
com2 db 'COM2',0
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
rdbuf db 20 dup(?) ; Buffer for input.
; Entries for choosing communications port. [19b]
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
ourarg termarg <>
datas ends
code segment public
extrn comnd:near, dopar:near, prserr:near, atoi:near, prompt:near
assume cs:code,ds:datas
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Do nothing since we are not interrupt driven. Returns normally.
CLRBUF PROC NEAR
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov ah,prstr
mov dx,offset clreol
int dos
ret
CLEARL ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov dl,al
mov ah,punout ; Output char in DL to comm port.
int dos
pop dx
jmp rskp
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov ah,prstr
mov dx,offset crlf ; Can't do anything else.
int dos
ret
CMBLNK ENDP
; Homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; Write a line at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov dx,1800h ; now address line 24
call poscur
pop dx ; get message back
mov ah,prstr
int dos ; write it out
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,1800h
call poscur ; Go to bottom row.
call clearl ; Clear to end of line.
ret
clrmod endp
; Put a help message on the screen.
; Pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push ax ; preserve this
mov ah,prstr
mov dx,offset crlf
int dos
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
mov dl,al
mov ah,dconio
int dos ; else write to screen
jmp puthl3 ; and keep going
puthl4: mov ah,prstr
mov dx,offset crlf
int dos
ret
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
DOBAUD PROC NEAR
mov ah,prstr
mov dx,offset noimp ; Say it's not implemented.
int dos
mov bx,portval
mov [bx].baud,0FFFFH ; So it's not a recognized value.
ret ; Must be set before starting Kermit.
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
ret ; Can't do this.
GETBAUD ENDP
; Use for DOS 2.0 and above. Check the port status. If no data, skip
; return. Else, read in a char and return.
PRTCHR PROC NEAR
push bx
push cx
push si
push bp
call chkxon
mov bx,prthnd
mov al,instat
mov ah,ioctl
int dos
or al,al
jz prtch4 ; not ready...
mov bx,prthnd
mov ah,rddev
mov cx,1
mov dx,offset temp
int dos
cmp al,5 ; Error condition.
je prt3x
cmp al,6 ; Error condition
je prt3x
mov al,byte ptr temp
mov bp,portval
cmp ds:[bp].parflg,PARNON ; no parity?
je prtch3 ; then don't strip
and al,7fh ; else turn off parity
prtch3: pop bp
pop si
pop cx
pop bx
ret
prt3x: mov ah,prstr
mov dx,offset erms50
int dos
prtch4: pop bp
pop si
pop cx
pop bx
jmp rskp ; no chars...
PRTCHR ENDP
; Local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent the xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
ret
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
; Set the current port.
COMS PROC NEAR
mov dx,offset comptab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
ret
coms0: mov ax,offset port2
mov portval,ax
ret
comx: pop bx
ret
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
jmp notimp
VTS ENDP
notimp: mov ah,prstr
mov dx,offset noimp
int dos
jmp prserr
; Initialize variables to values used by the generic MS DOS version.
lclini: mov flags.vtflg,0 ; Don't to terminal emulation.
call opnprt ; Get file handle for comm port.
ret
; Get a file handle for the communications port. Use DOS call to get the
; next available handle. If it fails, ask user what value to use (there
; should be a predefined handle for the port, generally 3). The open
; will fail if the system uses names other than "COM1" or "COM2".
opnprt: mov al,flags.comflg
mov ah,0
mov si,ax
shl si,1 ; double index
mov dx,prttab[si]
mov ah,open
mov al,2
int dos
jnc opnpr2
mov ah,prstr ; It didn't like the string.
mov dx,offset erms41
int dos
mov dx,offset hnd1
int dos
opnpr0: mov dx,offset hnd2 ; Ask user to supply the handle.
call prompt
mov ah,cmtxt
mov bx,offset rdbuf ; Where to put input.
mov dx,offset hndhlp ; In case user wants help.
call comnd
jmp opnpr3 ; Maybe user typed a ^C.
nop
mov si,offset rdbuf
call atoi ; Convert to real number
jmp opnpr0 ; Keep trying.
nop
mov prthnd,ax ; Value returned in AX
ret
opnpr2: mov prthnd,ax ; Call succeeded.
ret
opnpr3: cmp flags.cxzflg,'C' ; Did user type a ^C?
jne opnpr4 ; No, don't say anything.
mov ah,prstr ; Else, issue a warning.
mov dx,offset hnderr
int dos
opnpr4: ret ; Yes, fail.
showkey:
mov ax,offset shkmsg
mov cx,shklen
ret
; Initialization for using serial port. Returns normally.
SERINI PROC NEAR
cld ; Do increments in string operations
call clrbuf ; Clear input buffer.
ret ; We're done.
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
ret ; All done.
SERRST ENDP
; Produce a short beep. The PC DOS bell is long enough to cause a loss
; of data at the port. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,dconio
int dos
ret
BEEP ENDP
; Dumb terminal emulator. Doesn't work too well above 1200 baud (and
; even at 1200 baud you sometimes lose the first one or two characters
; on a line).
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
rep movsb ; copy into our arg blk
term1: call prtchr
jmp short term2 ; have a char...
nop
nop
jmp short term3 ; no char, go on
term2: push ax
and al,7fh ; mask off parity for terminal
mov dl,al
mov ah,conout
int dos ; go print it
pop ax
test ourarg.flgs,capt ; capturing output?
jz term3 ; no, forget it
call ourarg.captr ; else call the routine
term3: mov ah,dconio
mov dl,0ffh
int dos
jz term1 ; no character, go on
cmp al,ourarg.escc ; escape char?
je term4 ; yes, exit
push ax ; save char
mov ah,al
or ah,80H ; turn on hi bit so DOS doesn't interfere
call outchr ; output the character
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz term1 ; no, continue loop
mov dl,al
mov ah,dconio
int dos
jmp term1 ; else echo and keep going
term4: ret
term endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxgen.asm
/bin/echo -n ' '; /bin/ls -ld msxgen.asm
fi
More information about the Comp.sources.unix
mailing list