home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
09
/
bd.asm
< prev
next >
Wrap
Assembly Source File
|
1992-04-22
|
239KB
|
5,856 lines
page 55,132
title "BACKDOWN - Background Download Program"
; ---------------------------------------------------------------------
;
; Maintenance Log
;
; Version Date Description Who
; ------- ------- ---------------------------------- ----------------
; 1.0 08Feb91 Initial version complete Flanders/Holmes
;
; ---------------------------------------------------------------------
mainline segment para 'CODE' ; mainline
assume cs:mainline, ds:mainline, es:mainline, ss:mainline
org 100h
begin: jmp start ; start processing
VERSN equ "1.0" ; Version
; ---------------------------------------------------------------------
; macros
; ---------------------------------------------------------------------
CALLDI macro
db 0ffh, 0d7h ; call near ptr di
endm
; ---------------------------------------------------------------------
; interrupt vector control
; ---------------------------------------------------------------------
intblkcnt = 7 ; number of int routines
intblklen = 15 ; length of blocks
intblk1 equ offset oldint13 ; first to fill in
oldint13 dd 0 ; old cs:ip
oldss13 dd 0 ; ss:sp when int invoked
newss13 dd 0 ; work stack during int
db 13h ; interrupt to take over
dw offset int13 ; new interrupt routine
oldint2f dd 0 ; old cs:ip
oldss2f dd 0 ; ss:sp when int invoked
newss2f dd 0 ; work stack during int
db 2fh ; interrupt to take over
dw offset int2f ; new interrupt routine
oldint09 dd 0 ; old cs:ip
oldss09 dd 0 ; ss:sp when int invoked
newss09 dd 0 ; work stack during int
db 09h ; interrupt to take over
dw offset int09 ; new interrupt routine
oldint08 dd 0 ; old cs:ip
oldss08 dd 0 ; ss:sp when int invoked
newss08 dd 0 ; work stack during int
db 08h ; interrupt to take over
dw offset int08 ; new interrupt routine
oldint28 dd 0 ; old cs:ip
oldss28 dd 0 ; ss:sp when int invoked
newss28 dd 0 ; work stack during int
db 28h ; interrupt to take over
dw offset int28 ; new interrupt routine
dd 0 ; old cs:ip (comm interrupt)
dd 0 ; ss:sp when int invoked
dd 0 ; work stack during int
hd_int db 0 ; interrupt to take over
dw offset bd_int ; new interrupt routine
oldint10 dd 0 ; old cs:ip
oldss10 dd 0 ; ss:sp when int invoked
newss10 dd 0 ; work stack during int
db 10h ; interrupt to take over
dw offset int10 ; new interrupt routine
oldss dw 0 ; caller's stack segment
oldsp dw 0 ; ..and offset
; ---------------------------------------------------------------------
; TSR work variables, etc.
; ---------------------------------------------------------------------
nxtavail dw mem_end ; next available byte
startclr dw 0 ; addr to start mem clear
clrlen dw 0 ; length to clear
psp_seg dw 0 ; segment of our psp
dos_busy dd 0 ; addr of dos busy flag
i28hflag db 0 ; used by DOS Waiting rtn
intsbusy db 0 ; interrupts busy flag
i08hflg dw 0 ; int 08 in use
NCHARS = 10 ; Number of chars/dispatch
chars_disp dw NCHARS ; .. set the work word
tsr_active db 0 ; tsr pop'd up flag
tsr_req db 0 ; tsr requested flag
main_active db 1 ; main rtn entered
io_base dw 1 ; base port address
io_int db 0 ; ..and interrupt
dos_rc db 1 ; dos return code
db "Hot key>" ; visual ptr for hot key
shift_mask db 0ch ; ..and shift mask
; .... ...1 right shift
; .... ..1. left shift
; .... .1.. control key
; .... 1... alt key
hot_key db 30h ; scan code of hotkey (B)
multiplex dw 0c000h ; multiplex id for int 2fh
tsr_loaded dw 0 ; segment of TSR portion
scriptf_len = 64 ; length of filename field
scriptfile db scriptf_len dup (0) ; startup script filename
main_state dw 0 ; current state
main_table dw bd_trm ; 0 = terminal mode
dw bd_dnld ; 2 = download from terminal mode
dw exec_script ; 4 = running a script
dw bd_dnld ; 6 = download from a script
bd_userdata db 10 dup (0) ; B+ user data
bd_bstring db "B", 0, 0 ; B+ dl startup string
bd_bpinit db 10h, '++', 10h, '0' ; ENQ response string
; ---------------------------------------------------------------------
; protocol file management
; ---------------------------------------------------------------------
fileinfo struc ; find first/next structure
fiReserved db 21 dup (0) ; reserved
fiAttr db 0 ; attribute
fiTime dw 0 ; time last mod
fiDate dw 0 ; date last mod
fiSize dd 0 ; length of file
fiName db 13 dup (0) ; name of file
fileinfo ends
bdprot struc ; protocol structure
bdpchar db 0 ; invocation charcter
bdpname db 17 dup (0) ; protocol name
bdpnbr db 0 ; protocol nbr in module
bdpfile db 65 dup (0) ; protocol file name
bdprot ends
bdprotlen = 84 ; entry length
; ---------------------------------------------------------------------
; download protocol interface items
; ---------------------------------------------------------------------
bd_work dw 0 ; work register save area
bd_isi dw 0 ; incoming string pointer
bd_state dw -2 ; current download state
; download interface states
dw bd_gstringx ; -8 get a string (part II)
dw bd_ok ; -6 last request succeeded
dw bd_failed ; -4 last request failed
dw bd_init ; -2 initialize protocol
bd_table dw bd_call ; 0 call download
dw bd_open ; 2 open an output file
dw bd_write ; 4 write a file
dw bd_close ; 6 close a file
dw bd_delete ; 8 delete file
dw bd_done ; 10 finished w/protocol
dw bd_dstring ; 12 display string
dw bd_dbyte ; 14 display a character
dw bd_gstring ; 16 get a string
dw bd_sstring ; 18 send characters
dw bd_sbyte ; 20 send one character
dw bd_ticks ; 22 set tick down counter
dw bd_xstring ; 24 display w/o CR xlate
bd_handle dw 0 ; dl file handle
bd_offset dw 0 ; overlay area
bd_proto dd 0 ; protocol entry point
badproto db "Bad protocol selected",13,0
protonfnd db "Protocol file missing",13,0
bd_prompt db 13,"Enter protocol letter and parameters: ",0
; ---------------------------------------------------------------------
; screen management items
; ---------------------------------------------------------------------
pop_video dw 0 ; video page
pop_cursor dw 0 ; cursor position
cursor_line equ byte ptr pop_cursor+1 ; pointer to current row
cursor_col equ byte ptr pop_cursor ; pointer to current column
pop_cmode dw 001fh ; cursor mode
disp_seg dw 0 ; seg for bd_disp routine
disp_bufseg dw 0 ; seg for our display buf
lines = 25 ; 25 lines
cols = 80 ; .. of 80 columns
monoattr = 07h ; monochrome attribute
colattr = 1fh ; color attribute
ourattr db 07h ; attr to use, default mono
; ---------------------------------------------------------------------
; script execution work areas
; ---------------------------------------------------------------------
script_ids db 12h, 34h, 31h ; script file id/version bytes
SCRIPT_ID equ word ptr script_ids ; pointer to ID bytes
SCRIPT_VER equ byte ptr script_ids+2 ; pointer to version
script_amt dw 1024 ; script buffer size
script_buf dw 0 ; start of script buffer
script_wrk dw 0 ; current IP in script buffer
script_var dw 0 ; addr of next script variable
script_wsl dw 0 ; length of entered text
script_ws db 64 dup (0) ; work string area
script_fn db 64 dup (0) ; file name
script_cs db 14 ; current state
script_dm dw 1 ; debug mask
; .... ...1 disp received text
; .... ..1. disp sent text
script_dmx dw 0 ; xtra debug mask (for reply)
script_isi dw 0 ; incoming script parameter
recurse_lim db 5 ; recursion limit
next_token dw 0 ; addr of next input token
timeout dw (182 * 5)/10 ; timeout value in ticks (5sec)
timeout_lbl dw -1 ; offset of timeout label
tick_wait dw 0 ; tick wait downcounter
cancel_flag db 0 ; cancel flag
dot_bdc db "." ; .BDC ..
bdc db "BDC",0 ; script file extension
exec_fnf db 13,"Script file not found",13,0
exec_too db 13,"Script file too large",13,0
exec_nbdc db 13,"Script not compiled. Compile at the DOS prompt "
db "with the following command."
db 13," BD /c {script_filename}",13,0
exec_nver db 13,"Wrong version script. Please recompile.",13,0
scriptfull db 13,"Script buffer full",13,0
cancelmsg db 13,"Script terminated by operator",13,7,0
script_pt db 13,"Script name: ",0
exec_cmds dw exec_done ; 0 script done
dw exec_init ; 1 initialize port
dw exec_send ; 2 send string
dw exec_oper ; 3 notify operator
dw exec_reply ; 4 wait for reply
dw exec_tout ; 5 set timeout
dw exec_hang ; 6 hangup
dw exec_down ; 7 download file
dw exec_prompt ; 8 prompt for variable
dw exec_wait ; 9 wait (setup)
dw exec_goto ; 10 goto label
dw exec_rwait ; 11 reply wait loop
dw exec_wait1 ; 12 wait loop
dw exec_pwait ; 13 prompt wait loop
dw exec_start ; 14 look for new script
dw exec_opt ; 15 options cmd
dw exec_equate ; 16 equate cmd
replacables dw 9 + 26 dup (0) ; %1 - %9 and %A - %Z ptr array
user_i1b dw int23 ; ^Break handler
user_i1bs dw 0 ; segment ..
user_i23 dw int23 ; ^C handler
user_i23s dw 0 ; segment ..
user_i24 dw int24 ; critical error handler
user_i24s dw 0 ; segment ..
; ---------------------------------------------------------------------
; communications interrupt and buffering
; ---------------------------------------------------------------------
io_bdiv dw 48 ; current baud divisor (2400)
io_lcr db lcr_n81 ; ..and comm parms (N81)
ier = 1 ; offset of int enable reg
iir = 2 ; offset of int id reg
lcr = 3 ; offset of line ctl reg
mcr = 4 ; offset of modem ctl reg
lsr = 5 ; offset of line stat reg
msr = 6 ; offset of modem stat reg
dl_lsb = 0 ; lsb of divisor if DLAB=1
dl_msb = 1 ; msb of divisor if DLAB=1
ier_all = 00001111b ; enable all interrupts
; - line status register definition
lsr_drdy = 00000001b ; data ready
lsr_orun = 00000010b ; overrun error
lsr_prty = 00000100b ; parity error
lsr_frm = 00001000b ; framing error
lsr_brk = 00010000b ; break interrupt
lsr_thre = 00100000b ; transmit holding reg empty
lsr_tsre = 01000000b ; transmit shift register emtpy
lsr_err = lsr_frm+lsr_prty+lsr_orun ; error conditions
; - line control register definition
lcr_wlen = 00000011b ; word length:
; 10 = 7 bits, 11 = 8 bits
lcr_stop = 00000100b ; stop bits:
; 0 = 1 stopbit
; 1 = 2 stopbits
lcr_parity = 00001000b ; Parity enable
; 0 = No parity
; 1 = Send/Check parity
lcr_even = 00010000b ; Even/Odd parity
; 0 = Odd parity
; 1 = Even parity
lcr_break = 01000000b ; Break: set to xmit break
lcr_dlab = 10000000b ; divisor latch access bit
; - modem control register definitions
mcr_dtr = 00000001b ; turn on DTR
mcr_rts = 00000010b ; turn on Req to Send
mcr_out2 = 00001000b ; out2 control bit
mcr_DO = mcr_dtr+mcr_rts+mcr_out2 ; dtr, rts & out2
; - common definitions
lcr_N81 = 00000011b ; set 8 data, no parity, 1 stop
lcr_E71 = 00011010b ; set 7 data, even par, 1 stop
lcr_O71 = 00001010b ; set 7 data, odd par, 1 stop
; - line status register definitions
lsr_datardy = 00000001b ; data byte ready to read
lsr_overrun = 00000010b ; data overrun occurred
lsr_parerr = 00000100b ; parity error
lsr_framerr = 00001000b ; framing error
lsr_break = 00010000b ; break occurred
lsr_thre = 00100000b ; xmit hold reg empty
lsr_tsre = 01000000b ; xmit shift reg empty
; - modem status register definitions
msr_dcts = 00000001b ; delta clear to send
msr_ddsr = 00000010b ; delta data set ready
msr_teri = 00000100b ; trailing edge ring indicator
msr_dcd = 00001000b ; delta carrier detect
msr_cts = 00010000b ; clear to send
msr_dsr = 00100000b ; data set ready (modem ready)
msr_ri = 01000000b ; ring indicated
msr_cd = 10000000b ; carrier detected
; - 8259 programmable interrupt controller definitions
i8259 = 20h ; 8259 control register addr
eoi = 20h ; 8259 end of interrupt command
i8259m = 21h ; 8259 mask register
; - common control characters
soh = 01h ; start of header
stx = 02h ; start of text
etx = 03h ; end of text
ack = 06h ; acknowledge
nak = 15h ; non-acknowledge
; - definition of disk transfer area
dta = 0h ; default dta offset
dta_attr equ byte ptr dta+21 ; file attribute
dta_time equ word ptr dta_attr+1 ; file time
dta_date equ word ptr dta_time+2 ; file date
dta_lsiz equ word ptr dta_date+2 ; file lsw of size
dta_hsiz equ word ptr dta_lsiz+2 ; file msw of size
dta_name equ byte ptr dta_hsiz+2 ; file name of file
dta_len equ dta_name+15-dta ; length of dta find entry
dta_default = 80h ; default dta address
bd_int_use db 0 ; interrupt in use
last_msr db ? ; last msr seen
last_lsr db ? ; last lsr seen
;last_iir db ? ; last iir seen
; -------------------------------------------------------------------
; send buffer pointers
; -------------------------------------------------------------------
send_equsiz = 512 ; buffer size
send_bufget dw 0 ; get offset - used by int
send_bufseg dw ? ; segment for send buffer
send_bufint equ dword ptr send_bufget ; far ptr for next get
send_bufsiz dw send_equsiz ; size of send buffer
send_bufput dw 0 ; put offset - used by send
send_done db 1 ; all characters sent
; -------------------------------------------------------------------
; receive buffer pointers
; -------------------------------------------------------------------
rcv_equsiz = 520 * 2 ; buffer size
rcv_bufput dw 0 ; put offset - used by int
rcv_bufseg dw ? ; segment for rcv buffer
rcv_bufint equ dword ptr rcv_bufput ; far ptr for next put
rcv_bufsiz dw rcv_equsiz ; size of rcv buffer
rcv_bufget dw 0 ; get offset - used by rcv
rcv_ovfl db 0 ; overflow occurred flag
; -------------------------------------------------------------------
; terminal interface messages and data areas
; -------------------------------------------------------------------
bd_help$ db 13, " BackDown ", VERSN
db 13, "╔═════════════════════════════════════════════╗"
db 13, "║ F2: Settings F4: Break F10: Script ║"
db 13, "║ F3: Hangup F9: DownLoad Alt-X: DOS/Exit ║"
db 13, "╚═════════════════════════════════════════════╝"
bd_cr$ db 13, 0
bd_set$ db 13, " Speed Comm Parms "
db "Display B+ Protocol", 13, 13
db "A = 9600 1 = 8,None,1 7 = 7 Bit + = Enabled", 13
db "B = 2400 2 = 7,Odd, 1 8 = 8 Bit - = Disabled", 13
db "C = 1200 3 = 7,Even,1 ", 13
db "D = 300", 13
bd_set1$ db 13, "<CR> to end, Enter a choice:", 0
bd_hang$ db 13, "<<HANGUP>>", 13, 7, 0
bd_break$ db "<<Break>>", 0
case_flag db 1 ; ignore case in R cmds
enq_flag db 1 ; ENQ respected for B+
data_7flag db 1 ; 7bit mode for terminal
bd_bptable db "A", 6 ; A - 9600 baud
dw bd_selbaud
db "9600 Baud", 0
db "B", 24 ; B - 2400 baud
dw bd_selbaud
db "2400 Baud", 0
db "C", 48 ; C - 1200 baud
dw bd_selbaud
db "1200 Baud", 0
db "D", 192 ; D - 300 baud
dw bd_selbaud
db "300 Baud", 0
db "1", lcr_N81 ; 1 - N81
dw bd_selline
db "8,None,1", 0
db "2", lcr_O71 ; 2 - O71
dw bd_selline
db "7,Odd,1", 0
db "3", lcr_E71 ; 3 - E71
dw bd_selline
db "7,Even,1", 0
db "7", 1 ; A - 7BIT mode
dw bd_sel78
db "7 Bit Mode", 0
db "8", 0 ; B - 8BIT mode
dw bd_sel78
db "8 Bit Mode", 0
db "+", 1 ; C - B+ enabled
dw bd_selbp
db "B+ Enabled", 0
db "-", 0 ; D - B+ disabled
dw bd_selbp
db "B+ Disabled", 0
db 0 ; end of table marker
prottype db 13, "Type ", 0
proteq db " for ", 0
protnl db 13, " ", 0
noprots db "No protocol modules available", 13, 10
noprots_1 db "$"
; -------------------------------------------------------------------
; interrupt jump table
; -------------------------------------------------------------------
bdintab dw offset bdi_msi ; modem status interrupt
dw offset bdi_thre ; transmit done
dw offset bdi_rcv ; receive interrupt
dw offset bdi_lsi ; line status interrupt
; -------------------------------------------------------------------
; bd_int - communications interrupt handler
; -------------------------------------------------------------------
bd_int proc near ; interrupt handler entry point
push ax ; save registers
push bx
push dx
mov dx, cs:io_base ; dx = io base register
bdint10: add dx, iir ; dx = int id reg
in al, dx ; al = int id
sub dx, iir ; dx = base register
test al, 1 ; q. any interrupt?
jnz bdint90 ; a. no .. exit now.
xor ah, ah ; make it a word
mov bx, ax ; bx = interrupt id
call cs:word ptr bdintab[bx] ; .. call appropriate rtn
jmp bdint10 ; .. see if another
bdint90: mov al, eoi ; al = eoi instruction
out i8259, al ; .. reset the 8259
pop dx ; restore registers
pop bx
pop ax
iret ; return to interrupted code
bd_int endp
; -------------------------------------------------------------------
; bdi_msi - process modem status interrupt
;
; entry: dx = io_base
; -------------------------------------------------------------------
bdi_msi proc near
add dx, msr ; dx -> msr
in al, dx ; .. get the msr
sub dx, msr ; .. return to io_base
mov cs:last_msr, al ; save last msr value
ret ; .. return to caller
bdi_msi endp
; -------------------------------------------------------------------
; bdi_lsi - process line status interrupt
;
; entry: dx = io_base
; -------------------------------------------------------------------
bdi_lsi proc near
add dx, lsr ; dx -> lsr
in al, dx ; .. get the msr
sub dx, lsr ; .. return to io_base
or cs:last_lsr, al ; save last lsr value
ret ; .. return to caller
bdi_lsi endp
; -------------------------------------------------------------------
; bdi_rcv - process received character interrupt
;
; entry: dx = io_base
; -------------------------------------------------------------------
bdi_rcv proc near
in al, dx ; Get the character
push ds ; save the DS register
lds bx, cs:rcv_bufint ; ds:bx -> next rcv byte
mov byte ptr [bx], al ; save the char
pop ds ; restore ds
inc bx ; bx -> next position
cmp bx, cs:rcv_bufsiz ; q. end of buffer?
jne bdi_rcv10 ; a. no .. continue
xor bx, bx ; .. else .. reset pointer
bdi_rcv10: cmp bx, cs:rcv_bufget ; q. overrun?
jne bdi_rcv90 ; a. no .. save ptr & leave
mov cs:rcv_ovfl,1 ; show an overrun occurred
ret ; .. and return to caller
bdi_rcv90: mov cs:rcv_bufput, bx ; save buffer pointer
ret
bdi_rcv endp
; -------------------------------------------------------------------
; bdi_thre - process transmit holding register empty interrupt
;
; entry: dx = io_base
; -------------------------------------------------------------------
bdi_thre proc near
mov bx, cs:send_bufget ; bx = get pointer
cmp bx, cs:send_bufput ; q. buffer empty?
je bdi_thre90 ; a. yes .. exit now
mov cs:send_done, 0 ; show send not done
push ds ; save ds
lds bx, cs:send_bufint ; ds:bx -> next put byte
mov al, byte ptr [bx] ; al = char to send
out dx, al ; .. send the char
pop ds ; restore ds
inc bx ; bx -> next position
cmp bx, cs:send_bufsiz ; q. end of buffer?
jne bdi_thre10 ; a. no .. continue
xor bx, bx ; .. else .. bx = 0
bdi_thre10: mov cs:send_bufget, bx ; save the buffer pointer
ret ; .. return to caller
bdi_thre90: mov cs:send_done, 1 ; show the send is done
ret ; .. return to caller
bdi_thre endp
; -------------------------------------------------------------------
; ch_send - send a char
;
; al = char to send
; -------------------------------------------------------------------
ch_send proc near
push bx ; save regs
push dx ;
push es
mov es, send_bufseg ; es -> send segment
ch_send10: mov bx, send_bufput ; bx -> next out position
mov es:[bx], al ; write to output buffer
inc bx ; bx -> next pos
cmp bx, send_bufsiz ; q. end of buffer?
jne ch_send20 ; a. no .. continue
xor bx, bx ; .. else .. reset pointer
ch_send20: cmp bx, send_bufget ; q. buffer full?
je ch_send10 ; a. yes .. try again
mov send_bufput, bx ; save bufput addr
cmp send_done, 0 ; q. prime pump?
je ch_send90 ; a. no .. done for now.
mov dx, io_base ; dx = io base
add dx, lsr ; ds = lsr
ch_send30: in al, dx ; al = lsr
test al, lsr_thre ; q. xmit hold reg empty?
jz ch_send30 ; a. no .. loop 'til it is
sub dx, lsr ; dx = base register
call bdi_thre ; .. prime the pump
ch_send90: pop es ; restore registers
pop dx
pop bx
ret ; return to caller
ch_send endp
; -------------------------------------------------------------------
; any_ch - test for char in buffer
;
; exit: zero flag = no character available
; -------------------------------------------------------------------
any_ch proc near
mov ax, rcv_bufget ; ax -> next get char
cmp ax, rcv_bufput ; q. any put char?
ret ; a. return zf to caller
any_ch endp
; -------------------------------------------------------------------
; ch_get - get a char from buffer
;
; exit: ah = overflow flag
; al = char
; carry = no character available
; -------------------------------------------------------------------
ch_get proc near
push bx ; save regs
push es
xor ah, ah ; ah = 0
xchg ah, rcv_ovfl ; ah = overflow flag
mov bx, rcv_bufget ; bx = get address
cmp bx, rcv_bufput ; q. buffer empty?
je ch_get80 ; a. yes .. show the user
mov es, rcv_bufseg ; es -> buffer
mov al, es:[bx] ; al = next char in buf
inc bx ; bx -> next position
cmp bx, rcv_bufsiz ; q. end of buffer?
jne ch_get10 ; a. no .. continue
xor bx, bx ; .. else .. restart ptr
ch_get10: mov rcv_bufget, bx ; save next get ptr
clc ; show char received
jmp short ch_get90 ; .. return to caller
ch_get80: stc ; show no char available
ch_get90: pop es ; restore regs
pop bx
ret ; return to caller
ch_get endp
; ---------------------------------------------------------------------
; io_init - initialize the async port and 8259
; ---------------------------------------------------------------------
io_init proc near
xor dx, dx ; dx = base offset
call in_reg ; .. clear any character
mov dx, ier ; dx = ier offset
xor al, al ; al = zero (no interrupts)
call out_reg ; no ints for now
mov dx, mcr ; dx = mcr offset; al still 0
call out_reg ; .. set off all stats
mov dx, lsr ; dx = line status register
call in_reg ; read/reset interrupt reg
mov dx, msr ; dx = modem status register
call in_reg ; read/reset interrupt reg
mov dx, iir ; dx = interrupt id register
call in_reg ; read/reset interrupt reg
xor dx, dx ; dx = data register
call in_reg ; read/reset pending interrupts
call io_baud ; set baud rate
call io_pards ; ..and comm parms
mov dx, mcr ; dx = modem control reg offset
mov al, mcr_DO ; al = set on DTR, OUT2 and RTS
call out_reg ; .. set mcr value
in al, i8259m ; al = current int mask
mov cl, io_int ; cl = interrupt to use
mov ah, 1 ; ah = 1 ..
shl ah, cl ; .. shift bit to mask pos
not ah ; .. and invert mask
and al, ah ; .. set off mask bit
out i8259m, al ; .. allow com interrupts
mov dx, ier ; dx = int enable reg offset
mov al, ier_all ; al = allow all interrupts
call out_reg ; .. set int enable register
ret ; .. return to caller
io_init endp
; ----------------------------------------------------------------------
; in_reg - get a register's value from the UART
;
; entry: dx = register offset
;
; exit: al = value
; ----------------------------------------------------------------------
in_reg proc
add dx, io_base ; dx = register wanted
in al, dx ; .. get the value
ret ; return to caller
in_reg endp
; ----------------------------------------------------------------------
; out_reg - send a value out to a port
;
; entry: dx = reg offset
;
; exit: al = value
; ----------------------------------------------------------------------
out_reg proc
add dx, io_base ; dx = register wanted
out dx, al ; .. send the value
ret ; return to caller
out_reg endp
; ----------------------------------------------------------------------
; io_reset - reset and shutdown com port hardware interrupts
; ----------------------------------------------------------------------
io_reset proc
mov dx, mcr ; dx = modem control reg offset
xor al, al ; al = reset mcr
call out_reg ; .. reset mcr value
mov dx, ier ; dx = int enable reg offset
call out_reg ; .. reset int enable register
in al, i8259m ; al = current int mask
mov cl, io_int ; cl = interrupt to use
mov ah, 1 ; ah = 1 ..
shl ah, cl ; .. shift bit to mask pos
or al, ah ; .. set on mask bit
out i8259m, al ; .. allow com interrupts
ret ; .. return to caller
io_reset endp
; ----------------------------------------------------------------------
; io_baud - set baud rate
;
; entry: io_bdiv = baud rate divisor
; ----------------------------------------------------------------------
io_baud proc
push ax ; save registers
push dx
mov dx, lcr ; dx = lcr offset
call in_reg ; get current lcr
mov ah, al ; ah = old lcr
or al, lcr_dlab ; set on dlab
mov dx, lcr ; dx = lcr offset
cli ; no interrupts ..
call out_reg ; .. set on the dlab
mov dx, dl_msb ; dx = div latch msb
mov al, byte ptr io_bdiv+1 ; al = msb of divisor
call out_reg ; .. set the msb up
mov dx, dl_lsb ; dx = div latch lsb
mov al, byte ptr io_bdiv ; al = lsb of divisor
call out_reg ; .. set the lsb up
mov al, ah ; al = old lcr
mov dx, lcr ; dx = lcr offset
call out_reg ; .. turn off dlab
sti ; .. allow ints again
pop dx ; restore registers
pop ax
ret
io_baud endp
; ----------------------------------------------------------------------
; io_pards - set parity, stop, data bits
;
; entry: io_lcr = line control data
; ----------------------------------------------------------------------
io_pards proc
push dx ; save register
mov al, io_lcr ; al = comm parms
mov dx, lcr ; dx = lcr offset
call out_reg ; .. set comm parms
pop dx ; restore register
ret ; return to caller
io_pards endp
; ---------------------------------------------------------------------
; io_hangup - break a connection using DTR
; ---------------------------------------------------------------------
io_hangup proc
push ax ; save registers
push bx
push dx
mov dx, mcr ; dx = modem control
call in_reg ; al = mcr
mov dx, mcr ; dx = modem control
and al, not mcr_dtr ; al = shut off DTR
call out_reg ; .. shut down DTR
mov bx, 3 ; bx = ticks to wait
call tmr_wait ; .. wait .2 secs
call io_init ; re-init the uart
mov bx, 18 ; bx = time to wait
call tmr_wait ; .. wait a second
pop dx ; restore registers
pop bx
pop ax
ret ; .. return to caller
io_hangup endp
; ----------------------------------------------------------------------
; ck_dtr - check if DTR has dropped
; ----------------------------------------------------------------------
ck_dtr proc
push ax ; save registers
push dx
mov dx, mcr ; dx = modem control reg offset
call in_reg ; get mcr value
and al, mcr_dtr ; q. DTR up?
jnz ck_dtr90 ; a. yes .. return
call io_init ; initialize port and mcr
mov bx, 9 ; bx = time to wait
call tmr_wait ; .. wait half a second
ck_dtr90: pop dx ; restore registers
pop ax
ret ; .. then return to caller
ck_dtr endp
; ---------------------------------------------------------------------
; tmr_wait - wait some number of ticks
;
; entry: bx = ticks to wait
; ---------------------------------------------------------------------
tmr_wait proc
mov tick_wait, bx ; number of ticks to wait
tmr_wait10: cmp tick_wait, 0 ; q. waited enough?
jge tmr_wait10 ; a. no .. wait some more
ret ; return to caller
tmr_wait endp
; ---------------------------------------------------------------------
; io_break - send a break
; ---------------------------------------------------------------------
io_break proc
push ax ; save registers
push bx
push dx
mov dx, lcr ; dx = lcr offset
call in_reg ; al = lcr value
mov ah, al ; ah = old lcr value
or al, lcr_break ; set break bit in al
mov dx, lcr ; dx = lcr offset
call out_reg ; .. send the break
mov bx, 9 ; bx = length of break
call tmr_wait ; .. wait .5 secs
mov al, ah ; al = old lcr value
mov dx, lcr ; dx = lcr offset
call out_reg ; .. restore lcr
pop dx ; restore registers
pop bx
pop ax
ret
io_break endp
; ----------------------------------------------------------------------
; usingdos - returns the availability of DOS for file i/o
;
; exit: carry = DOS not ready for file i/o
;
; ----------------------------------------------------------------------
usingdos proc
cmp intsbusy, 0 ; q. one of interrupts busy?
jne usingdos95 ; a. yes .. exit w/wait code
push es ; save registers
push bx ; ..
les bx, dos_busy ; es:bx -> DOS busy flag
cmp word ptr es:[bx], 0 ; q. DOS available?
je usingdos80 ; a. yes .. tell caller ok
cmp i28hflag, 0 ; q. called from DOS Waiting
je usingdos90 ; a. no .. DOS is busy
cmp byte ptr es:[bx+1], 1 ; q. DOS available during int 28
jne usingdos90 ; a. yes .. tell caller ok
usingdos80: pop bx ; ...restore registers
pop es ; ...
clc ; show DOS is available ..
ret ; ..and return to caller
usingdos90: pop bx ; ...restore registers
pop es ; ...
usingdos95: stc ; show DOS busy ..
ret ; ..and return to caller
usingdos endp
; ----------------------------------------------------------------------
; main - this routine is the main control tsr loop
; ----------------------------------------------------------------------
main proc
inc cs:main_active ; show main in use
cmp cs:main_active, 1 ; q. already in main?
je main10 ; a. no .. continue
dec cs:main_active ; decrement our use
ret ; else .. just return
main10: push ax ; save registers
push ds
push es
mov ax, cs ; ax -> us
mov ds, ax ; ds -> our data
mov es, ax ; es -> there too
mov oldss, ss ; save caller's stack
mov oldsp, sp ;
cli ; hold up interrupts
mov ss, ax ; setup new stack
mov sp, offset wstack ; ..
sti ; enable interrupts
push bx ; save rest on our stack
push cx
push dx
push si
push di
push bp
cld ; clear direction flag
cmp tsr_req, 0 ; q. need to pop up?
je main20 ; a. no .. continue
call usingdos ; q. DOS available?
jc main20 ; a. no .. continue
call popup ; else .. pop up our screen
main20: mov bx, main_state ; bx = current state
call main_table[bx] ; dispatch to term, dl, script
cmp tsr_active, 0 ; q. are we popped up?
jne main20 ; a. yes .. stay in main
call any_ch ; q. any chars in buffer?
jz main90 ; a. no .. exit now
dec chars_disp ; q. enough chars/dispatch?
jnz main20 ; a. no .. one more time
main90: mov chars_disp, NCHARS ; refill dispatch quantity
pop bp ; restore registers
pop di
pop si
pop dx
pop cx
pop bx
cli ; hold interrupts
mov ss, oldss ; restore caller's stack
mov sp, oldsp ; ..
sti ; enable interrupts again
pop es ; restore more registers
pop ds
pop ax
dec cs:main_active ; ..show we're out of here
ret ; ..and return to caller
main endp
; ----------------------------------------------------------------------
; int28 - DOS waiting interrupt handler
; ----------------------------------------------------------------------
int28 proc
sti ; enable interrupts
inc cs:i28hflag ; show we're in int 28 rtn
call main ; do a small amount of work
dec cs:i28hflag ; show we're out of int 28
jmp dword ptr cs:oldint28 ; jump to old int 28 routine
int28 endp
; ----------------------------------------------------------------------
; int13 - Disk I/O in progress interrupt handler
; ----------------------------------------------------------------------
int13 proc far
push bp ; save caller's bp
mov bp, sp ; bp -> stack
push [bp+6] ; push caller's flags
mov bp, [bp] ; ..restore bp contents
inc cs:intsbusy ; show interrupt is busy
call dword ptr cs:oldint13 ; call the old int 13 rtn
pushf ; save int 13 return flags
dec cs:intsbusy ; now show we're done
popf ; ..restore int 13's flags
pop bp ; ..remove BP from stack
ret 2 ; ..and return to caller
int13 endp
; ----------------------------------------------------------------------
; int10 - BIOS Video call in progress interrupt handler
; ----------------------------------------------------------------------
int10 proc far
pushf ; save int 10 return flags
sti ; enable interrupts
inc cs:intsbusy ; show interrupt is busy
call dword ptr cs:oldint10 ; call the old int 10 rtn
dec cs:intsbusy ; now show we're done
iret ; ..and return to caller
int10 endp
; ----------------------------------------------------------------------
; int2f - multiplexor interrupt handler
;
; exit: di = tsr segment if ax = multiplex nbr
; ----------------------------------------------------------------------
int2f proc ; multiplex interrupt
cmp ax, cs:multiplex ; q. for us?
jne i2fh90 ; a. no .. try someone else
mov di, cs ; di -> our segment
iret ; ..then return to caller
i2fh90: jmp dword ptr cs:oldint2f ; chain to old int 2f rtn
int2f endp
; ----------------------------------------------------------------------
; int08 - timer tick interrupt handler
; ----------------------------------------------------------------------
int08 proc
pushf ; fake interrupt call
call cs:oldint08 ; call old timer stuff
dec cs:tick_wait ; downcount timer ticks
call main ; call our main routine
iret ; ..and return to caller
int08 endp
; ----------------------------------------------------------------------
; int09 - keyboard interrupt handler
; ----------------------------------------------------------------------
int09 proc
cmp cs:tsr_active, 0 ; q. tsr in use?
jne i09h15 ; a. yes .. get out quickly
push ax ; save used register
in al, 60h ; get key scan code
cmp al, cs:hot_key ; q. our hot-key?
je i09h10 ; a. yes .. continue
pop ax ; restore register
jmp short i09h15 ; ..and get out
i09h10: mov ah, 2 ; ah = get shift status fnc
int 16h ; call BIOS
and al, 0fh ; al = 'shift' bits
cmp al, cs:shift_mask ; q. match our combo?
pop ax ; restore register
je i09h20 ; a. yes . continue
i09h15: jmp cs:oldint09 ; else .. do key as normal
i09h20: pushf ; call old int 9
call cs:oldint09 ; ..to finish reading key
sti ; allow interrupts
push ax ; save work register
i09h30: mov ah, 1 ; ah = get status
int 16h ; q. any keys availabl?
jz i09h40 ; a. no .. exit loop
mov ah, 0 ; ah = get key
int 16h ; get the key ..
jmp i09h30 ; ..and loop till kb empty
i09h40: pop ax ; restore register
inc cs:tsr_req ; show tsr request made
iret ; go back where we came from
int09 endp
; ----------------------------------------------------------------------
; int23 - ^C and ctrl-break interrupt handler
; ----------------------------------------------------------------------
int23 proc
iret ; just return to caller
int23 endp
; ----------------------------------------------------------------------
; int24 - critical error handler
; ----------------------------------------------------------------------
int24 proc
mov al, 3 ; al = failed call
iret ; ..then return to caller
int24 endp
; ----------------------------------------------------------------------
; popup - pop up our window
; ----------------------------------------------------------------------
popup proc
sti ; allow interrupts
mov tsr_req, 0 ; clear tsr request flag
mov ah, 0fh ; get current display mode
int 10h ; .. ask BIOS
mov bx, 0b800h ; bx = assume color adapter
cmp al, 2 ; q. bw mode?
je popup10 ; a. yes .. ok to do it.
cmp al, 3 ; q. color mode?
je popup10 ; a. yes .. ok to do it.
mov bx, 0b000h ; bx = assume mono adapter
cmp al, 7 ; q. mono mode?
jne popup90 ; a. no .. we're history
popup10: mov disp_seg, bx ; set bd_disp segment
call swap_1b ; swap ^break handler in
inc tsr_active ; show we're pop'd up
call swap_screen ; swap screens
popup90: ret ; ..then return to caller
popup endp
; ----------------------------------------------------------------------
; popdown - pop down our screen
; ----------------------------------------------------------------------
popdown proc
call swap_screen ; swap screens
mov bx, disp_bufseg ; bx = segment for bd_disp
mov disp_seg, bx ; setup for display routine
call swap_1b ; swap ^break handler out
dec tsr_active ; show we're pop'down
mov tsr_req, 0 ; ..and clear any requests
ret ; ..then return to caller
popdown endp
; ----------------------------------------------------------------------
; swap_screen - swap tsr screen with display memory
;
; exit: carry = bad video mode mode
; ----------------------------------------------------------------------
swap_screen proc
mov ah, 0fh ; ah = get current info
int 10h ; call BIOS
xchg pop_video, bx ; save current video page
mov al, bh ; al = active page
mov ah, 5 ; ah = setup active page
int 10h ; call BIOS
mov ah, 3 ; ah = get cursor position
int 10h ; call BIOS
xchg pop_cursor, dx ; save cursor position
xchg pop_cmode, cx ; ..and cursor mode
mov ah, 1 ; ah = set cursor mode
int 10h ; .. do it
mov ah, 2 ; ah = set cursor position
int 10h ; call BIOS
push ds ; save registers
push es
mov es, disp_bufseg ; es -> our screen buffer
xor di, di ; di = offset in our buf
mov ds, disp_seg ; ds -> video buffer
xor si, si ; si = offset in vid buf
mov cx, 80 * 25 ; columns to swap
swap_sc20: mov ax, es:[di] ; ax = char/attr @our buf
xchg ax, ds:[si] ; swap with buffer
inc si ; si -> next
inc si ; .. char
stosw ; .. complete the exchange
loop swap_sc20 ; .. continue 'til done
pop es ; restore registers
pop ds
ret ; return to caller
swap_screen endp
; ----------------------------------------------------------------------
; bd_trm - terminal interface routine.
; ----------------------------------------------------------------------
bd_trm proc near
call bd_key ; q. key ready?
jc bd_trm50 ; a. no .. display chars
or al, al ; q. special key?
jnz bd_trm10 ; a. no .. continue
call bd_skey ; process special keys
jmp short bd_trm50 ; ..then get a com character
bd_trm10: call ch_send ; send the character
bd_trm50: call ch_get ; q. character available?
jc bd_trm90 ; a. no .. do main loop
call bd_bpstuff ; handle CIS B+ and 7 bit stuff
jc bd_trm90 ; ..if processed.. continue
call bd_disp ; display the char gotten
jmp bd_trm ; .. see if anything typed
bd_trm90: ret ; return to caller
bd_trm endp
; ----------------------------------------------------------------------
; bd_disp - display a character on screen
;
; entry: al = char to display
; ----------------------------------------------------------------------
bd_disp proc near ; display char on screen
push ax ; save registers
push bx
push si
push di
or al, al ; q. nul character?
jnz bd_disp10 ; a. no .. let's show it!
jmp bd_disp90 ; .. else .. exit
bd_disp10: cmp tsr_active, 0 ; q. popped up?
je bd_disp50 ; a. no .. process in memory
mov ah, 0eh ; ah = write, tty style
xor bx, bx ; .. bh = page, bl = FG color
int 10h ; .. write w/BIOS
cmp al, 8 ; q. backspace?
je bd_disp20 ; a. yes .. process it
jmp bd_disp90 ; .. else .. exit
bd_disp20: mov ax, 0e20h ; al = write a blank
int 10h ; .. write w/ bios
mov ax, 0e08h ; al = write another bs
int 10h ; .. write w/ bios
jmp bd_disp90 ; .. and return to caller
bd_disp50: cmp al, 0dh ; q. above <CR>
ja bd_disp70 ; a. yes .. display it
jb bd_disp55 ; a. below .. check it out
mov cursor_col, 0 ; move cursor to first char
jmp short bd_disp90 ; .. and exit
bd_disp55: cmp al, 0ah ; q. <LF>?
jne bd_disp60 ; a. no .. continue
cmp cursor_line, 24 ; q. at "bottom"?
jne bd_disp57 ; a. no .. increment
call bd_scroll ; else .. scroll
jmp short bd_disp90 ; .. and continue
bd_disp57: inc cursor_line ; increment line
jmp short bd_disp90 ; .. and continue
bd_disp60: cmp al, 08h ; q. backspace?
jne bd_disp65 ; a. no .. continue
cmp cursor_col, 0 ; q. at start of line?
je bd_disp90 ; a. yes .. go no further
dec cursor_col ; move back a char
mov al, ' ' ; change to blank
call bd_disp ; .. display the blank
dec cursor_col ; .. move back again
jmp short bd_disp90 ; .. and continue
bd_disp65: cmp al, 07h ; a. bell?
jne bd_disp70 ; a. no .. continue
mov ah,0eh ; ah = write tty
int 10h ; .. tweet-tweet
jmp short bd_disp90 ; .. and continue
bd_disp70: push ax ; save character
mov bx, pop_cursor ; bx = cursor postion
mov al, bh ; al = row
xor ah, ah ; .. clear upper bits
mov bh, 160 ; bh = row len
mul bh ; .. get row offset
xor bh, bh ; kill the upper bits
shl bx, 1 ; bx = bx * 2 (Line offset)
add bx, ax ; bx -> byte offset for line
pop ax ; ax = entry contents
push es ; save es
mov es, disp_bufseg ; .. get pointer to buffer
mov es:[bx], al ; .. save the byte
pop es ; .. restore es
inc cursor_col ; go to next position
cmp cursor_col, 80 ; q. end of line?
jb bd_disp90 ; a. no .. we are done
mov cursor_col, 0 ; reset the row
cmp cursor_line, 24 ; q. at "bottom"
jne bd_disp80 ; a. no .. increment
call bd_scroll ; else .. scroll
jmp short bd_disp90 ; .. and exit
bd_disp80: inc cursor_line ; next line
bd_disp90: pop di ; restore registers
pop si
pop bx
pop ax
ret ; return to caller
bd_disp endp
; ----------------------------------------------------------------------
; bd_scroll - scroll the display buffer up one line
; ----------------------------------------------------------------------
bd_scroll proc
push cx ; save registers
push si
push di
push ds
push es
xor di, di ; di -> start of buffer
mov si, 160 ; si -> second line
mov cx, 24*80 ; scroll up 24 lines
mov es, disp_bufseg ; es -> display buffer
mov ds, disp_bufseg ; .. and ds
cld ; .. clear the direction
rep movsw ; .. scroll 'er up
mov cx, 80 ; cx = bytes in last to clear
mov al, ' ' ; al = blank
bd_scroll1: stosb ; clear a character
inc di ; .. skip the attribute
loop bd_scroll1 ; .. until all done
pop es ; restore regs
pop ds
pop di
pop si
pop cx
ret
bd_scroll endp
; ----------------------------------------------------------------------
; bd_skey - handle special keys
; ----------------------------------------------------------------------
bd_skey proc near
; - see if ALT-X (Exit)
cmp ah, 2dh ; q. alt-X?
jne bd_skeyf1 ; a. no .. check f1
call popdown ; restore screen
ret ; ..and return to caller
; - see if F1 (Help)
bd_skeyf1: cmp ah, 3bh ; q. F1? (Help)
jne bd_skeyf2 ; a. no .. check f2
mov si, offset bd_help$ ; si -> help message
call disp_msg ; display ASCIIZ msg
ret ; .. return to caller
; - see if F2 (Comm Parameters)
bd_skeyf2: cmp ah, 3ch ; q. F2? (Comm parms)
jne bd_skeyf3 ; a. no .. check f3
mov si, offset bd_set$ ; si -> parms message
lea di, bd_bptable ; di -> toggle table
call bd_select ; select an entry or two
ret ; return to caller
; - see if F3 (Hang Up)
bd_skeyf3: cmp ah, 3dh ; q. F3? (hangup)
jne bd_skeyf4 ; a. no .. check F4
call io_hangup ; else .. hang it up
mov si, offset bd_hang$ ; si -> message
call disp_msg ; .. display it
ret ; .. return to caller
; - see if F4 (Break)
bd_skeyf4: cmp ah, 3eh ; q. F4? (Break)
jne bd_skeyf9 ; a. no .. check F8
call io_break ; else .. send a break
mov si, offset bd_break$ ; si -> message
call disp_msg ; .. display it
ret ; .. return to caller
; - see if F9 (Download)
bd_skeyf9: cmp ah, 43h ; q. F9? (Download)
jne bd_skeyf10 ; a. no .. see if script
mov bx, offset bdprot1 ; bx -> 1st protocol
lea si, prottype ; si -> "Type " string
mov cx, bdprotn ; cx = loop count
or cx, cx ; q. any protocol modules?
jnz bd_skf9_10 ; a. yes .. continue
lea si, noprots ; si -> sorry none there msg
call disp_msg ; display error msg
ret ; ..and return to caller
bd_skf9_10: call disp_msg ; display header msg
mov al, [bx].bdpchar ; al = protocol letter
call bd_disp ; put it out
lea si, proteq ; si -> " = " msg
call disp_msg ; put it out too
lea si, [bx].bdpname ; si -> protocol name
call disp_msg ; display it also
lea si, protnl ; si -> <CR>" "
add bx, bdprotlen ; bx -> next table entry
loop bd_skf9_10 ; ..loop up till done
mov script_wsl, 0 ; reset string length
lea si, bd_prompt ; si -> prompt
call disp_msg ; display prompt
bd_skf9_20: call get_line ; q. get a complete line?
jnc bd_skf9_20 ; a. no .. try again
mov di, offset script_ws ; di -> inputted line
cmp byte ptr [di], 0 ; q. user enter anything?
je bd_skf9_30 ; a. no .. just continue
mov bd_isi, di ; save user response
add main_state, 2 ; show download active
bd_skf9_30: call exec_crlf ; do a cr/lf
ret ; ..and return to caller
; - see if F10 (Run Script)
bd_skeyf10: cmp ah, 44h ; q. F10? (Script)
jne bd_skey90 ; a. no .. error beep
mov script_wsl, 0 ; reset string length
mov si, offset script_pt ; si -> script prompt
call disp_msg ; display prompt
bd_skf10_1: call get_line ; q. get a complete line?
jnc bd_skf10_1 ; a. no .. try again
mov di, offset script_ws ; di -> inputted line
mov script_isi, di ; save script name
mov main_state, 4 ; show script state
call exec_crlf ; do a cr/lf
ret ; ..and return to caller
bd_skey90: mov al, 07h ; al = beep
call bd_disp ; ..tell 'em about the key
ret ; ..return to caller
bd_skey endp
; ----------------------------------------------------------------------
; bd_key - see if key available, get it if there is
;
; exit: ah = scan code
; al = ASCII or 0
; carry set = no key
; ----------------------------------------------------------------------
bd_key proc near
cmp tsr_active, 0 ; q. popped up?
je bd_key05 ; a. no .. no key available
mov ah, 1 ; ah = get kb status
int 16h ; q. any key hit?
jnz bd_key10 ; a. yes .. get the key
bd_key05: stc ; show no key available
ret ; .. return to caller
bd_key10: mov ah, 0 ; ah = get keystroke
int 16h ; .. read the kb
call ck_dtr ; check for DTR active
clc ; show key available
ret ; .. return to caller
bd_key endp
; ----------------------------------------------------------------------
; bd_select - Get/process key against menu table
;
; entry: bx = table entry length
; si -> header message
; di -> table to process against
; ----------------------------------------------------------------------
bd_select proc
bd_selec10: call disp_msg ; display the message
bd_selec20: call bd_key ; get a key
jc bd_selec20 ; .. try again if none
cmp al, 0dh ; q. <CR>?
jnz bd_selec30 ; a. no .. continue
mov si, offset bd_cr$ ; si -> ASCIIZ <CR>
call disp_msg ; .. display it
ret ; return to caller
bd_selec30: call comp_ul ; al = uppercase letter
mov si, di ; si -> table to work with
bd_selec40: cmp byte ptr [si], 0 ; q. end of list?
je bd_selec20 ; a. yes .. wait for good val
cmp al, [si] ; q. this entry?
je bd_selec50 ; a. yes .. process it
add si, 12 ; si -> a little way down string
bd_selec45: cmp byte ptr [si-1], 0 ; q. hit end of string?
je bd_selec40 ; a. yes .. check next operand
inc si ; si -> next character
jmp bd_selec45 ; ..check next char for EOS
bd_selec50: call word ptr [si+2] ; call routine for key
add si, 4 ; si -> message
call disp_msg ; .. display it
lea si, bd_set1$ ; si -> continuation message
jmp bd_selec10 ; ..loop up and try for another
bd_select endp
; ----------------------------------------------------------------------
; bd_selbaud - process baud selections
;
; entry: si -> table entry
; ----------------------------------------------------------------------
bd_selbaud proc
mov al, [si+1] ; al = divisor / 2
xor ah, ah ; ax = cast to (int)
shl ax, 1 ; ax = baud divisor
mov io_bdiv, ax ; ..save value
call io_init ; set the baud rate
ret ; ..then return to caller
bd_selbaud endp
; ----------------------------------------------------------------------
; bd_selline - process line selections
;
; entry: si -> table entry
; ----------------------------------------------------------------------
bd_selline proc
mov al, [si+1] ; al = lcr setting
mov io_lcr, al ; save for init routine
call io_init ; set the comm parms
ret ; ..then return to caller
bd_selline endp
; ----------------------------------------------------------------------
; bd_selbp - process B+ toggle
;
; entry: si -> table entry
; ----------------------------------------------------------------------
bd_selbp proc
mov al, [si+1] ; al = flag setting
mov enq_flag, al ; save for terminal routine
ret ; ..then return to caller
bd_selbp endp
; ----------------------------------------------------------------------
; bd_sel78 - process 7/8 bit display
;
; entry: si -> table entry
; ----------------------------------------------------------------------
bd_sel78 proc
mov al, [si+1] ; al = flag setting
mov data_7flag, al ; save for terminal routine
ret ; ..then return to caller
bd_sel78 endp
; ----------------------------------------------------------------------
; bd_bpstuff - handle CIS B+ launch sequences and 7 bit ASCII data
;
; entry: al = character
; exit: carry = character processed
; ----------------------------------------------------------------------
bd_bpstuff proc
cmp enq_flag, 0 ; q. allow CIS B+ sequences?
je bd_bpstu50 ; a. no .. continue
cmp al, 5 ; q. ENQ character?
jne bd_bpstu30 ; a. no .. continue
mov cx, 5 ; cx = count
lea si, bd_bpinit ; si -> init data
bd_bpstu10: lodsb ; al = char to display
call ch_send ; put out a character
loop bd_bpstu10 ; ..and loop back for next
lea di, bd_userdata ; di -> B+ user data
mov ax, 3000h ; ax = init constant
stosw ; ..save in user area
mov cx, 4 ; cx = repeat count
mov ax, 0ffffh ; ax = init constant
rep stosw ; initialize user area
stc ; carry = character processed
ret ; ..return to caller
bd_bpstu30: cmp al, 10h ; q. DLE character?
jne bd_bpstu50 ; a. no .. continue
mov bd_isi, offset bd_bstring ; save addr of proto cmd
add main_state, 2 ; show download active
stc ; carry = character processed
ret ; ..return to caller
bd_bpstu50: cmp data_7flag, 0 ; q. need to trim 7 bits?
je bd_bpstu90 ; a. no .. continue
and al, 07fh ; al = trimmed to size
bd_bpstu90: clc ; carry = not processed
ret ; ..and return to caller
bd_bpstuff endp
; ----------------------------------------------------------------------
; bd_dnld - interface to protocols
;
; when calling protocol module
; ax = current tick downcounter
;
; di = 0 initialization call bx -> oper dx = prot nbr
; 2 last fnc ok | wasting time
; 4 last fnc requested failed
; 6 comm character dl = character
; 8 keyboard character dl = character
;
; return from protocol module
; di = 0 ok
; 2 open output file bx -> filename
; 4 write file bx -> 2cnt + data
; 6 close file
; 8 delete file bx -> filename
; 10 done
; 12 display an ASCIIZ string bx -> string
; 14 display one character bl = character
; 16 get a line bx -> area
; 18 send characters over comm bx -> 2cnt + data
; 20 send one character bl = character
; 22 set tick downcounter bx = count
; 24 display without <CR> xlate bx -> string
;
; ----------------------------------------------------------------------
bd_dnld proc
mov bx, bd_work ; bx = work register
mov di, bd_state ; di = current state
bd_dnld10: call bd_table[di] ; call current state routine
jc bd_dnld10 ; ..loop again
mov bd_state, di ; save state for next time
mov bd_work, bx ; ..and work register
ret ; return to caller
bd_dnld endp
; ----------------------------------------------------------------------
; bd_failed - last function request failed
; ----------------------------------------------------------------------
bd_failed proc
mov di, 4 ; di = fail fnc code
mov ax, tick_wait ; ax = current tick value
call dword ptr bd_proto ; call protocol
clc ; clear carry = wait
ret ; ..and return to caller
bd_failed endp
; ----------------------------------------------------------------------
; bd_init - load and initialize a protocol
; ----------------------------------------------------------------------
bd_init proc
call setupdos ; q. dos available?
jnc bd_init10 ; a. yes .. continue
clc ; clear carry ..
ret ; else .. return to caller
bd_init10: call bd_lookup ; q. find bdp name/size
jnc bd_init20 ; a. yes .. continue
call swap_psp ; swap psp's again
mov si, offset badproto ; si -> error message
jmp short bd_init95 ; ..display and return
bd_init20: push bx ; save registers
push cx ;
mov ax, 3d00h ; ax = open file
int 21h ; issue DOS call
jnc bd_init30 ; ..if ok, continue
call swap_psp ; swap psp's again
mov si, offset protonfnd ; si -> file not found
jmp short bd_init95 ; ..display msg and return
bd_init30: mov bx, ax ; bx = file handle
mov ah, 3fh ; ah = read file
mov cx, bdplen ; cx = bdp overlay size
mov dx, bd_offset ; dx -> overlay area
int 21h ; issue DOS call
mov ah, 3eh ; ah = close file
int 21h ; issue DOS call
call swap_psp ; swap psp's again
xor di, di ; di = init call to protocol
pop dx ; dx = protocol nbr
pop bx ; ds:bx -> operands
mov ax, tick_wait ; ax = current tick value
lea si, bd_userdata ; si -> user area
call dword ptr bd_proto ; call protocol
clc ; clear carry = wait
ret ; ..then return to caller
bd_init95: call disp_msg ; display the error msg
sub main_state, 2 ; reset state to term/script
mov di, -2 ; di = init state
clc ; clear carry ..
ret ; else .. return to caller
bd_init endp
; ----------------------------------------------------------------------
; bd_lookup - lookup protocol in table
;
; entry: bd_isi -> entered string
; exit: dx -> filename to load
; bx -> operands to protocol
; cx = protocol number
; ----------------------------------------------------------------------
bd_lookup proc
mov bx, bd_isi ; bx -> operands string
mov bd_isi, 0 ; clear string pointer
mov next_token, bx ; setup tokenizer
call token ; di -> protocol letter
mov al, [di] ; al = requested protocol
call comp_ul ; al = uppercase letter
mov bx, offset bdprot1 ; bx -> table of protocols
mov cx, bdprotn ; cx = nbr of entries
bd_look10: cmp al, [bx].bdpchar ; q. find table entry?
je bd_look20 ; a. yes .. exit loop
add bx, bdprotlen ; bx -> next table entry
loop bd_look10 ; ..loop till found/done
stc ; carry = not found
ret ; ..then return to caller
bd_look20: lea dx, [bx].bdpfile ; dx -> filename
mov cl, [bx].bdpnbr ; cl = protocol nbr
xor ch, ch ; cx = (int) protocol nbr
call next ; di -> next operand
mov bx, di ; bx -> next operand
clc ; clear carry = ok
ret ; ..just return to caller
bd_lookup endp
; ----------------------------------------------------------------------
; bd_ok - last function request succeeded
; ----------------------------------------------------------------------
bd_ok proc
mov di, 2 ; di = ok fnc code
mov ax, tick_wait ; ax = current tick value
call dword ptr bd_proto ; call protocol
clc ; clear carry = wait
ret ; ..and return to caller
bd_ok endp
; ----------------------------------------------------------------------
; bd_call - things ok, just call protocol
; ----------------------------------------------------------------------
bd_call proc
call ch_get ; q. get a comm character?
jc bd_call20 ; a. no .. check keyboard
mov di, 6 ; di = comm char coming
mov dl, al ; dl = character
jmp short bd_call50 ; ..continue with common code
bd_call20: call bd_key ; q. get a keyboard character?
jc bd_call40 ; a. no .. continue
cmp ax, 2d00h ; q. Alt-X, pop down?
jne bd_call30 ; a. no .. continue
call popdown ; else .. close down our window
jmp short bd_call40 ; ..and call with "all ok"
bd_call30: mov di, 8 ; di = keyboard char coming
mov dx, ax ; dx = scan code & character
jmp short bd_call50 ; ..continue with common code
bd_call40: mov di, 2 ; di = everything's ok
bd_call50: mov ax, tick_wait ; ax = current tick value
call dword ptr bd_proto ; call protocol
clc ; clear carry = wait
ret ; ..and return to caller
bd_call endp
; ----------------------------------------------------------------------
; bd_open - open an output file for the protocol
; ----------------------------------------------------------------------
bd_open proc
call setupdos ; q. dos available?
jnc bd_open10 ; a. yes .. continue
clc ; clear carry ..
ret ; else .. return to caller
bd_open10: add bx, bd_offset ; bx -> file name in dl memory
mov ah, 3ch ; ah = create function
mov cx, 0 ; cx = normal file attribute
mov dx, bx ; ds:dx -> string
int 21h ; issue DOS call
jc bd_open90 ; ..on error try again
mov bd_handle, ax ; save the handle
mov di, -6 ; di = request ok
jmp short bd_open95 ; ..and exit via common point
bd_open90: mov di, -4 ; di = request failed
bd_open95: call swap_psp ; swap caller psp back
stc ; carry = do next state now
ret ; ..then return to caller
bd_open endp
; ----------------------------------------------------------------------
; bd_write - write file
; ----------------------------------------------------------------------
bd_write proc
call setupdos ; q. dos available?
jnc bd_write10 ; a. yes .. continue
clc ; clear carry ..
ret ; else .. return to caller
bd_write10: add bx, bd_offset ; bx -> count and data
mov ah, 40h ; ah = write file
mov cx, [bx] ; cx = count
lea dx, [bx+2] ; dx -> data
mov bx, bd_handle ; bx = file handle
int 21h ; issue DOS call
jc bd_write90 ; ..on error try again
mov di, -6 ; di = request ok
jmp short bd_write95 ; ..and exit via common point
bd_write90: mov di, -4 ; di = request failed
bd_write95: call swap_psp ; swap caller psp back
stc ; carry = do next state now
ret ; ..then return to caller
bd_write endp
; ----------------------------------------------------------------------
; bd_close - close file
; ----------------------------------------------------------------------
bd_close proc
call setupdos ; q. dos available?
jnc bd_close10 ; a. yes .. continue
clc ; clear carry ..
ret ; else .. return to caller
bd_close10: mov ah, 3eh ; ah = close file
mov bx, bd_handle ; bx = file handle
int 21h ; issue DOS call
call swap_psp ; swap caller psp back
mov bd_handle, 0 ; clear file handle field
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_close endp
; ----------------------------------------------------------------------
; bd_delete - delete file
; ----------------------------------------------------------------------
bd_delete proc
call setupdos ; q. dos available?
jnc bd_delet10 ; a. yes .. continue
clc ; clear carry ..
ret ; else .. return to caller
bd_delet10: push bx ; save register
mov ah, 3eh ; ah = close file
mov bx, bd_handle ; bx = file handle
int 21h ; issue DOS call
pop bx ; restore register
add bx, bd_offset ; bx -> filename to delete
mov ah, 41h ; ah = delete file
mov dx, bx ; ds:dx -> filename
int 21h ; issue DOS call
call swap_psp ; swap caller's psp back
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_delete endp
; ----------------------------------------------------------------------
; bd_done - download finished
; ----------------------------------------------------------------------
bd_done proc
mov bx, bd_handle ; bx = file handle
or bx, bx ; q. file open?
jz bd_done80 ; a. no .. continue
call setupdos ; q. dos usable?
jc bd_done90 ; a. no .. continue
mov ah, 3eh ; ah = close file
int 21h ; issue DOS call
call swap_psp ; swap caller psp back
bd_done80: sub main_state, 2 ; reset state to term/script
mov di, -2 ; di = init state
cmp tsr_active, 0 ; q. already pop'd up?
jne bd_done90 ; a. yes .. skip request
cmp main_state, 0 ; q. terminal mode again?
jne bd_done90 ; a. no .. probaly script
inc tsr_req ; else .. make window popup
bd_done90: clc ; ..ensure we leave the loop
ret ; ..and return to caller
bd_done endp
; ----------------------------------------------------------------------
; bd_dstring - display a null terminated string
; ----------------------------------------------------------------------
bd_dstring proc
add bx, bd_offset ; bx -> protocol's msg
mov si, bx ; si -> msg
call disp_msg ; call display
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_dstring endp
; ----------------------------------------------------------------------
; bd_xstring - display a null terminated string without <CR> translate
; ----------------------------------------------------------------------
bd_xstring proc
add bx, bd_offset ; bx -> protocol's msg
mov si, bx ; si -> msg
bd_xstr10: lodsb ; al = char to display
or al, al ; q. end of string?
jz bd_xstr90 ; a. yes .. leave
call bd_disp ; display the char
jmp bd_xstr10 ; .. get next char
bd_xstr90: mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_xstring endp
; ----------------------------------------------------------------------
; bd_dbyte - display a character
; ----------------------------------------------------------------------
bd_dbyte proc
mov al, bl ; al = character to display
call exec_dispx ; call display one character
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_dbyte endp
; ----------------------------------------------------------------------
; bd_gstring - get a string from user
; ----------------------------------------------------------------------
bd_gstring proc ; initialization procedure
mov script_wsl, 0 ; clear length byte
mov di, -8 ; di = wait state for get string
stc ; carry = do next state now
ret ; ..then return to caller
bd_gstring endp
bd_gstringx proc ; wait procedure
call get_line ; q. get a whole line?
jc bd_gstr10 ; a. yes .. continue
clc ; clear carry = wait a little
ret ; ..and return to caller
bd_gstr10: add bx, bd_offset ; bx -> user's data area
mov cx, script_wsl ; cx = length
mov si, offset script_ws ; si -> work area
mov di, bx ; di -> destination
call string_copy ; copy to protocol's area
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_gstringx endp
; ----------------------------------------------------------------------
; bd_sstring - send a string out the comm port
; ----------------------------------------------------------------------
bd_sstring proc
add bx, bd_offset ; bx -> string to send
mov cx, [bx] ; cx = count
lea si, [bx + 2] ; si -> data
bd_sstr10: lodsb ; al = char to display
call ch_send ; put out a character
loop bd_sstr10 ; ..and loop back for next
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_sstring endp
; ----------------------------------------------------------------------
; bd_sbyte - send a byte out the comm port
; ----------------------------------------------------------------------
bd_sbyte proc
mov al, bl ; al = character to send
call ch_send ; put out a character
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_sbyte endp
; ----------------------------------------------------------------------
; bd_ticks - set the down counter timer
; ----------------------------------------------------------------------
bd_ticks proc
mov tick_wait, bx ; set downcounter
mov di, -6 ; di = request ok
stc ; carry = do next state now
ret ; ..then return to caller
bd_ticks endp
; ----------------------------------------------------------------------
; setupdos - setup to use DOS
;
; exit: carry = DOS isn't ready yet
; ----------------------------------------------------------------------
setupdos proc
call usingdos ; q. can we use DOS?
jc setupdos90 ; a. no .. return to caller
call swap_psp ; swap psp and handlers
clc ; clear carry flag
setupdos90: ret ; ..and return to caller
setupdos endp
; ----------------------------------------------------------------------
; exec_script - script state machine dispatcher
; ----------------------------------------------------------------------
exec_script proc
push ax ; save registers
push bx
push cx
push dx
push si
push di
push es
call exec_term ; display incoming
jc exec_scr90 ; ..and exit if ENQ recieved
call exec_key ; handle keyboard
mov bl, script_cs ; bl = current state number
xor bh, bh ; bx = cmd number
shl bx, 1 ; bx = command offset
mov si, script_wrk ; si -> compiled command
call exec_cmds[bx] ; call current state rtn
call exec_cancel ; check for cancel request
mov script_wrk, si ; save current location
exec_scr90: pop es ; restore registers
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret ; ..then return to caller
exec_script endp
; ----------------------------------------------------------------------
; exec_start - start script execution
;
; entry: script_isi -> script name/parms
; exit: si -> start of script
; ----------------------------------------------------------------------
exec_start proc
mov si, script_isi ; si -> script name/parms
or si, si ; q. anything there?
jnz exec_sta00 ; a. yes .. try to open it
ret ; else .. just return
exec_sta00: call usingdos ; q. using DOS?
jnc exec_sta05 ; a. no .. continue
ret ; else .. just return
exec_sta05: mov script_isi, 0 ; clear script name pointer
mov cancel_flag, 0 ; ..and cancel flag
mov next_token, si ; save start of command
call token ; di -> filename
jnc exec_sta10 ; if ok, continue
call exec_done ; clean up ..
ret ; ..and return
exec_sta10: call string_len ; cx = string length
mov si, offset script_fn ; si -> script filename
push si ; save registers
push si ;
xchg si, di ; si -> token, di -> field
call string_copy ; copy script filename local
pop di ; di -> script filename
mov al, '.' ; al = search character
repne scasb ; q. find the period?
je exec_sta15 ; a. yes .. continue
mov cx, 5 ; cx = length of .ext
mov si, offset dot_bdc ; si -> compiled script extension
call string_copy ; copy our extension
exec_sta15: pop dx ; dx -> script filename
call swap_psp ; swap psp's
mov ax, 3d00h ; ax = open file for read
int 21h ; call DOS function
jnc exec_sta20 ; ..if ok, continue
call swap_psp ; swap psp's back
mov si, offset exec_fnf ; si -> script not found msg
call disp_msg ; put out message
call exec_done ; reset our state
ret ; ..and return to caller
exec_sta20: mov bx, ax ; bx = file handle
mov ax, 4202h ; ax = seek to eof
xor cx, cx ; cx = offset of zero
xor dx, dx ; dx = zero, too
int 21h ; call DOS function
or dx, dx ; q. larger that 64k?
jnz exec_sta25 ; a. yes .. bad news
cmp ax, script_amt ; q. larger than allocated space?
jle exec_sta30 ; a. no .. continue
exec_sta25: call swap_psp ; swap psp's back
mov si, offset exec_too ; si -> script too large msg
call disp_msg ; put out message
call exec_done ; reset our state
ret ; ..and return to caller
exec_sta30: push ax ; save file size
push ax ; ..twice
mov ax, 4200h ; ax = seek to top of file
xor cx, cx ; cx = offset of zero
int 21h ; call DOS function
mov ah, 3fh ; ah = read file
mov cx, 3 ; cx = length to read
mov dx, script_buf ; ds:dx -> buffer
int 21h ; call DOS function
mov si, dx ; si -> script buffer
mov ax, [si] ; ax = 1st two bytes from file
mov dx, offset exec_nbdc ; dx -> script not compiled
cmp ax, SCRIPT_ID ; q. compiled file?
jne exec_sta35 ; a. no .. error message
mov dx, offset exec_nver ; dx -> script wrong version
mov al, SCRIPT_VER ; al = version supported
cmp al, [si+2] ; q. right version?
je exec_sta40 ; a. yes.. continue
exec_sta35: mov ah, 3eh ; ah = close file
int 21h ; call DOS function
add sp, 4 ; backout both pushes
call swap_psp ; swap psp's back
mov si, dx ; si -> error message
call disp_msg ; put out message
call exec_done ; reset our state
ret ; ..and return to caller
exec_sta40: mov ah, 3fh ; ah = read file
pop cx ; cx = length to read
mov dx, script_buf ; ds:dx -> buffer
int 21h ; call DOS function
mov ah, 3eh ; ah = close file
int 21h ; call DOS function
call swap_psp ; swap psp's back
pop si ; si = length of script
add si, script_buf ; si -> replacables area
mov cx, 9 + 26 ; cx = nbr of replacables
mov bx, offset replacables ; bx -> pointer array
exec_sta50: call token ; di -> token
jc exec_sta60 ; ..on error, just clear entry
mov [bx], si ; save addr of token
push cx ; save registers
call comp_copy ; copy to script buffer
pop cx ; restore loop count
inc si ; si -> next usable location
jmp short exec_sta70 ; ..continue with common code
exec_sta60: mov word ptr [bx], 0 ; clear pointer entry
exec_sta70: add bx, 2 ; bx -> next pointer entry
loop exec_sta50 ; ..and loop till done
mov script_var, si ; save addr for next variable
mov si, script_buf ; si -> start of script
call exec_ncmd ; setup to handle first cmd
ret ; ..and returning to caller
exec_start endp
; ----------------------------------------------------------------------
; exec_ncmd - handle next command
;
; entry: si -> next script command
; ----------------------------------------------------------------------
exec_ncmd proc
call ck_dtr ; check DTR is active
mov al, [si] ; al = next command byte
mov script_cs, al ; store as current state
inc si ; si -> command | data byte
ret ; ..then return to caller
exec_ncmd endp
; ----------------------------------------------------------------------
; exec_key - handle unrequested keys during script
; ----------------------------------------------------------------------
exec_key proc
cmp script_cs, 13 ; q. waiting at a prompt?
je exec_key90 ; a. yes .. exit
call bd_key ; q. get a key?
jc exec_key90 ; a. no .. continue
cmp al, 1bh ; q. ESC key?
jne exec_key10 ; a. no .. continue
mov cancel_flag, 1 ; show cancel requested
jmp short exec_key90 ; ..and return to caller
exec_key10: cmp ax, 2d00h ; q. Alt-X, pop down?
jne exec_key90 ; a. no .. continue
call popdown ; else .. close down our window
exec_key90: ret ; ..and return to caller
exec_key endp
; ----------------------------------------------------------------------
; exec_cancel - check for cancel request
; ----------------------------------------------------------------------
exec_cancel proc
cmp cancel_flag, 0 ; q. need to cancel?
je exec_can90 ; a. no .. continue
mov si, offset cancelmsg ; si -> terminated msg
call disp_msg ; put out message
call exec_done ; cleanup/ready for next time
exec_can90: ret ; ..then return to caller
exec_cancel endp
; ----------------------------------------------------------------------
; exec_done - end of script
; ----------------------------------------------------------------------
exec_done proc
mov script_cs, 14 ; clear script state
mov main_state, 0 ; put back in terminal mode
inc tsr_req ; make window popup
ret ; ..and return to caller
exec_done endp
; ----------------------------------------------------------------------
; exec_init - port and options initialization
; ----------------------------------------------------------------------
exec_init proc
xor bx, bx ; bx = io_init needed flag
mov al, [si] ; al = baud rate divisor
or al, al ; q. need to change baud?
jz exec_in10 ; a. no ..continue
xor ah, ah ; ah = cast as integer
shl ax, 1 ; ax = divisor
mov io_bdiv, ax ; save for init routine
inc bx ; show io_init needed
exec_in10: mov al, 1[si] ; al = line control register
or al, al ; q. need to lcr?
jz exec_in20 ; a. no ..continue
mov io_lcr, al ; save for init rtn too
inc bx ; show io_init needed
exec_in20: or bx, bx ; q. need to call io_init?
jz exec_in30 ; a. no .. continue
call io_init ; call uart init routine
exec_in30: mov al, 2[si] ; al = 7/8 toggle info
or al, al ; q. changing modes?
jz exec_in40 ; a. no .. continue
dec al ; al = flag
mov data_7flag, al ; setup in toggle
exec_in40: mov al, 3[si] ; al = B+ toggle info
or al, al ; q. changing modes?
jz exec_in50 ; a. no .. continue
dec al ; al = flag
mov enq_flag, al ; setup in toggle
exec_in50: mov al, 4[si] ; al = case compare option
or al, al ; q. changing modes?
jz exec_in60 ; a. no .. continue
dec al ; al = flag
mov case_flag, al ; setup in toggle
exec_in60: add si, 5 ; si -> next command
call exec_ncmd ; handle next command
ret ; ..and return to caller
exec_init endp
; ----------------------------------------------------------------------
; exec_opt - display options command
; ----------------------------------------------------------------------
exec_opt proc
mov ax, [si] ; ax = debug bits
mov script_dm, ax ; save display mask
add si, 2 ; si -> next command
call exec_ncmd ; handle next command
ret ; ..and return to caller
exec_opt endp
; ----------------------------------------------------------------------
; exec_send - send text to host computer
; ----------------------------------------------------------------------
exec_send proc
test script_dm, 2 ; q. display outgoing?
jz exec_se10 ; a. no .. continue
push si ; save string pointer
call exec_disp ; display what we're sending
pop si ; restore register
exec_se10: mov di, offset ch_send ; di -> send char routine
call exec_expand ; ..expand string and send
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_send endp
; ----------------------------------------------------------------------
; exec_oper - write message to operator's display
; ----------------------------------------------------------------------
exec_oper proc
call exec_disp ; expand string & display
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_oper endp
; ----------------------------------------------------------------------
; exec_reply - wait a reply (setup)
; ----------------------------------------------------------------------
exec_reply proc
mov ax, timeout ; ax = current timeout value
mov tick_wait, ax ; setup timeout timer
mov script_wsl, 0 ; looking for 1st character
mov script_cs, 11 ; setup for new state
mov ax, script_dm ; get current mask
mov script_dmx, ax ; save temporarily
and script_dm, 0fffeh ; turn off display bit
ret ; ..and return
exec_reply endp
; ----------------------------------------------------------------------
; exec_rwait - wait for a host reply (loop)
; ----------------------------------------------------------------------
exec_rwait proc
mov bx, script_wsl ; bx = offset in string
exec_rwa10: cmp cancel_flag, 0 ; q. cancel request?
jne exec_rwa18 ; a. yes .. patch up and exit
cmp tick_wait, 0 ; q. timeout yet?
jg exec_rwa20 ; a. no .. continue
mov al, 7 ; give timeout beep
call bd_disp ; ..let'em know we're here
mov bx, timeout_lbl ; bx = offset of timeout
cmp bx, -1 ; q. do next statement?
je exec_rwa40 ; a. yes .. find next statement
exec_rwa15: mov si, bx ; si -> timeout label
call exec_ncmd ; setup to handle next cmd
exec_rwa18: mov ax, script_dmx ; get old debug bits
mov script_dm, ax ; ..and restore it
jmp short exec_rwa70 ; ..and exit via common point
exec_rwa20: call ch_get ; q. get a character?
jc exec_rwa80 ; a. no .. come back later
call bd_bpstuff ; handle B+ and 7bit
jc exec_rwa80 ; ..if eaten, continue
test script_dmx, 1 ; q. want display as we go?
jz exec_rwa25 ; a. no .. continue
call bd_disp ; else .. show'em the incoming
exec_rwa25: mov cl, 1[bx+si] ; cl = char from wait string
cmp case_flag, 0 ; q. ignore case?
je exec_rwa28 ; a. no .. respect case
call comp_ul ; al = upcased host char
xchg cl, al ; al = wait string char
call comp_ul ; ..now upcased
xchg cl, al ; al = host char again
exec_rwa28: cmp al, cl ; q. match character?
je exec_rwa30 ; a. yes .. continue
or bx, bx ; q. have we found any yet?
jz exec_rwa10 ; a. no .. start again
xor bx, bx ; bx = start from beginning
jmp exec_rwa25 ; ..and this character
exec_rwa30: inc bx ; bump char found count
cmp byte ptr [si], bl ; q. find all characters yet?
jne exec_rwa10 ; a. yes .. goto next state
exec_rwa40: mov bl, [si] ; bl = length of string
xor bh, bh ; bx = length now
add si, bx ; si -> last character
inc si ; si -> next command
call exec_ncmd ; setup to handle next cmd
exec_rwa70: mov ax, script_dmx ; get old debug bits
mov script_dm, ax ; ..and restore it
exec_rwa80: mov script_wsl, bx ; save found count
ret ; ..and return to caller
exec_rwait endp
; ----------------------------------------------------------------------
; exec_tout - setup timeout value/location command
; ----------------------------------------------------------------------
exec_tout proc
mov ax, 0[si] ; ax = timeout value
mov timeout, ax ; save value for timeout counter
mov ax, 2[si] ; ax => timeout label
cmp ax, -1 ; q. just do next statement?
je exec_tout1 ; a. yes .. continue
add ax, script_buf ; ax -> timeout label
mov timeout_lbl, ax ; save offset for next timeout
exec_tout1: add si, 4 ; si -> next command
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_tout endp
; ----------------------------------------------------------------------
; exec_hang - hangup line command
; ----------------------------------------------------------------------
exec_hang proc
call io_hangup ; issue a hangup
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_hang endp
; ----------------------------------------------------------------------
; exec_down - download a file
; ----------------------------------------------------------------------
exec_down proc
mov cl, byte ptr 0[si] ; cl = length of command
xor ch, ch ; cx = len of command
inc si ; si -> next command
mov di, offset script_ws ; di -> work area
mov bd_isi, di ; save user response
call string_copy ; copy/ASCIIZ the string
add main_state, 2 ; show download active
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_down endp
; ----------------------------------------------------------------------
; exec_prompt - prompt for variable data (setup)
; ----------------------------------------------------------------------
exec_prompt proc
call exec_disp ; display prompt message
mov script_wsl, 0 ; clear entered count
mov script_cs, 13 ; setup new state to get data
ret ; ..and return to caller
exec_prompt endp
; ----------------------------------------------------------------------
; exec_pwait - wait for user to enter prompt data (loop)
; ----------------------------------------------------------------------
exec_pwait proc
call get_line ; q. get a line?
jc exec_pwa10 ; a. yes .. continue
ret ; else .. just return
exec_pwa10: mov di, script_var ; di -> next script buffer
mov ax, di ; ax -> next location
sub ax, script_buf ; ax = what's been used
mov cx, script_wsl ; cx = length of string w/null
add ax, cx ; ax = length after copy
cmp ax, script_amt ; q. going over our bounds?
jl exec_pwa20 ; a. no .. continue
mov si, offset scriptfull ; si -> script full message
call disp_msg ; display error message
call exec_done ; setup for next script
ret ; ..and return to caller
exec_pwa20: mov al, [si] ; al = index into repl table
cbw ; ax = index, too
shl al, 1 ; al = offset in table
mov bx, offset replacables ; bx -> replacables table
add bx, ax ; bx -> table entry
mov [bx], di ; save addr of this variable
push si ; save register
mov si, offset script_ws ; si -> input'ed string
xchg si, di ; si -> dest, di -> entered text
call comp_copy ; copy to script buffer
mov script_var, si ; save next usable addr
pop si ; restore instruction pointer
inc si ; si -> next command
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_pwait endp
; ----------------------------------------------------------------------
; exec_equate - equate a variable w/some text
; ----------------------------------------------------------------------
exec_equate proc
mov di, si ; di -> equate string
mov al, [si] ; al = length of string
cbw ; ax = len of string
add si, ax ; si -> last char of string
inc si ; si -> offset in variable tbl
mov al, [si] ; al = index into repl table
cbw ; ax = index, too
shl al, 1 ; al = offset in table
mov bx, offset replacables ; bx -> replacables table
add bx, ax ; bx -> table entry
mov [bx], di ; save addr of this variable
inc si ; si -> next command
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_equate endp
; ----------------------------------------------------------------------
; exec_wait - wait the script execution a couple of ticks (setup)
; ----------------------------------------------------------------------
exec_wait proc
mov ax, [si] ; ax = number of ticks
mov tick_wait, ax ; save value
mov script_cs, 12 ; setup for wait state
ret ; ..and return to caller
exec_wait endp
; ----------------------------------------------------------------------
; exec_wait1 - help wait a couple of ticks (loop)
; ----------------------------------------------------------------------
exec_wait1 proc
cmp tick_wait, 0 ; q. time expired?
jnz exec_wait2 ; a. yes .. exit loop
add si, 2 ; si -> next command
call exec_ncmd ; setup to handle next cmd
exec_wait2: ret ; ..and return to caller
exec_wait1 endp
; ----------------------------------------------------------------------
; exec_goto - goto label
; ----------------------------------------------------------------------
exec_goto proc
mov si, [si] ; get new pointer offset
add si, script_buf ; si -> new pointer
call exec_ncmd ; setup to handle next cmd
ret ; ..and return to caller
exec_goto endp
; ----------------------------------------------------------------------
; next - get next token start address
;
; entry: next_token -> where to start scan
; exit: di -> start of non-blank token
; carry set if no token available
; ----------------------------------------------------------------------
next proc
mov di, next_token ; di -> start of string
next10: cmp byte ptr [di], 0 ; q. at end of string?
je next90 ; a. yes .. exit loop
cmp byte ptr [di], ' ' ; q. blank?
jne next80 ; a. no .. exit loop
inc di ; di -> next character
jmp short next10 ; ..then loop
next80: clc ; show something found
ret ; ..and return to caller
next90: stc ; show null token
ret ; ..and return
next endp
; ----------------------------------------------------------------------
; token - get next token
;
; entry: next_token -> where to start scan
; exit: next_token -> where to start next scan
; di -> token, null terminated
; carry = no token available
; ----------------------------------------------------------------------
token proc
call next ; q. di -> start of string
jc token90 ; a. no .. just null char
push di ; save start point
token10: cmp byte ptr [di], 0 ; q. end of the line?
je token80 ; a. yes .. bail out now
cmp byte ptr [di], ' ' ; q. blank?
je token70 ; a. yes .. exit loop
inc di ; di -> next character
jmp short token10 ; ..then loop
token70: mov byte ptr [di], 0 ; make into null terminated string
inc di ; di -> 1st byte after this token
token80: mov next_token, di ; save next start location
pop di ; get this token's start
clc ; show token found
token90: ret ; ..and return to caller
token endp
; ----------------------------------------------------------------------
; exec_crlf - display a CR/LF
; ----------------------------------------------------------------------
exec_crlf proc
mov al, 0dh ; al = <CR>
call bd_disp ; display it
mov al, 0ah ; al = <LF>
call bd_disp ; ..and line feed too
ret ; ..then return to caller
exec_crlf endp
; ----------------------------------------------------------------------
; exec_disp - display string
;
; entry: si -> counted string
; ----------------------------------------------------------------------
exec_disp proc
push di ; save registers
mov di, offset exec_dispx ; di -> display char routine
call exec_expand ; ..expand string & display
pop di ; restore registers
ret ; ..and return to caller
exec_disp endp
; ----------------------------------------------------------------------
; exec_dispx - display a char with CR/LF handling
;
; entry: ax = char to display
; ----------------------------------------------------------------------
exec_dispx proc
cmp al, 0dh ; q. CR?
jne exec_dx9 ; a. no .. just continue
push ax ; save register
mov al, 0ah ; al = a linefeed character
call bd_disp ; put out the LF
pop ax ; restore the CR
exec_dx9: call bd_disp ; display original char
ret ; ..then return to caller
exec_dispx endp
; ----------------------------------------------------------------------
; exec_expand - process and expand string
;
; entry: si -> counted string
; di -> routine to call to output each character
; ----------------------------------------------------------------------
exec_expand proc
xor dl, dl ; dl = current recursion level
exec_ex00: push bx ; recursion entry point
push cx
inc dl ; dl = new recursion level
or si, si ; q. null pointer?
jz exec_ex90 ; a. yes .. just exit
mov cl, byte ptr [si] ; cl = length of string
xor ch, ch ; cx = length now
or cx, cx ; q. null string?
jz exec_ex90 ; a. yes .. exit here
inc si ; si -> first char of string
exec_ex10: lodsb ; al = character from string
cmp dl, recurse_lim ; q. hit limit?
jg exec_ex40 ; a. yes .. exit now
cmp al, '%' ; q. control character?
jne exec_ex40 ; a. no .. put it out
cmp cx, 1 ; q. last character
je exec_ex40 ; a. yes .. put out char
dec cx ; else .. take one off tally
lodsb ; al = next character
cmp al, '%' ; q. need a percent symbol?
je exec_ex40 ; a. yes .. put one out
cmp al, '1' ; q. within 1 to 9?
jl exec_ex40 ; a. no .. just put it out
cmp al, '9' ; q. numeric?
jg exec_ex20 ; a. no .. check alpha
sub al, '1' ; al = offset
jmp short exec_ex30 ; ..continue w/common code
exec_ex20: call comp_ul ; ..and make uppercase
cmp al, 'A' ; q. within A to Z?
jl exec_ex40 ; a. no .. just put it out
cmp al, 'Z' ; q. alpha?
jg exec_ex40 ; a. no .. just put it out
sub al, 'A' - 9 ; al = offset
exec_ex30: xor ah, ah ; ah = clear upper byte
shl ax, 1 ; ax = table offset
mov bx, offset replacables ; bx -> table
add bx, ax ; bx -> entry
mov bx, [bx] ; bx -> string to display
xchg bx, si ; si -> replacement string
call exec_ex00 ; put out string
mov si, bx ; si -> where we left off
jmp short exec_ex50 ; ..then continue in loop
exec_ex40: CALLDI ; al = char to send/display
exec_ex50: loop exec_ex10 ; ..then loop till end of string
exec_ex90: dec dl ; decriment recursion level
pop cx ; restore registers
pop bx
ret ; ..and return to caller
exec_expand endp
; ----------------------------------------------------------------------
; exec_term - display async stream during script
;
; exit: carry = special char received
; ----------------------------------------------------------------------
exec_term proc
test script_dm, 1 ; q. display as we go?
jz exec_ter85 ; a. no .. continue
mov cx, 100 ; cx = loop limit
exec_ter10: call ch_get ; q. character available?
jc exec_ter85 ; a. no .. exit loop
call bd_bpstuff ; handle B+ stuff
jc exec_ter90 ; ..if char processed
call bd_disp ; display recieved character
loop exec_ter10 ; ..then loop a while
exec_ter85: clc ; clear carry = just continue
exec_ter90: ret ; return to caller
exec_term endp
; ----------------------------------------------------------------------
; disp_msg - display a simple msg
;
; entry: si -> null terminated string
; ----------------------------------------------------------------------
disp_msg proc
push si ; save registers
disp_msg10: lodsb ; al = char to display
or al, al ; q. end of string?
jz disp_msg90 ; a. yes .. exit loop
call exec_dispx ; else .. put out character
jmp disp_msg10 ; ..and loop back for next
disp_msg90: pop si ; restore register
ret ; ..and return to caller
disp_msg endp
; ----------------------------------------------------------------------
; string_len - count null terminated string
;
; entry: di -> input string
; exit: cx = length
; ----------------------------------------------------------------------
string_len proc
push ax ; save registers
push di
mov al, 0 ; al = search argument
mov cx, 0ffh ; cx = max length
repne scasb ; search for null
mov ax, 0feh ; ax = init count
sub ax, cx ; ax = string length
mov cx, ax ; cx = length to return
pop di ; restore registers
pop ax
ret ; ..and return to caller
string_len endp
; ----------------------------------------------------------------------
; string_copy - null terminated string copy
;
; entry: si -> source
; di -> destination
; cx = max length
; exit: di -> destination null terminator
; ----------------------------------------------------------------------
string_copy proc
push ax ; save registers
push cx
string_co1: lodsb ; al = character from string
stosb ; store char @ destination
cmp al, 0 ; q. end of the line?
je string_c90 ; a. yes .. exit loop
loop string_co1 ; ..and loop till end of string
string_c90: pop cx ; restore registers
pop ax
ret ; ..and return
string_copy endp
; ----------------------------------------------------------------------
; get_line - get a line from user
;
; exit: no carry = string not complete
; carry = string completed
; script_ws = null term string
; script_wsl = length w/null
; ----------------------------------------------------------------------
get_line proc
push si ; save register
get_line00: call bd_key ; q. key ready?
jnc get_line10 ; a. yes .. check it out
clc ; clear finish flag
jmp short get_line95 ; ..and return to caller
get_line10: or al, al ; q. function key?
jz get_line00 ; a. yes .. get another key
cmp al, 0dh ; q. carriage return?
jne get_line20 ; a. no .. continue
call exec_crlf ; do a CR/LF
jmp short get_line90 ; ..then clean up and return
get_line20: cmp al, 8 ; q. backspace?
jne get_line30 ; a. no .. continue
cmp script_wsl, 0 ; q. anything in line?
je get_line00 ; a. no .. just get next char
dec script_wsl ; cx = one less
dec si ; si -> previous character
jmp short get_line40 ; ..display backspace
get_line30: cmp al, ' ' ; q. below a blank?
jl get_line00 ; a. yes .. get another
cmp al, 127 ; q. above a zee and "{|}~" ?
jg get_line00 ; a. yes .. get another
mov si, offset script_ws ; si -> work area
add si, script_wsl ; si -> next available character
mov [si], al ; store character in line
inc script_wsl ; save new length
get_line40: call bd_disp ; echo the character
cmp script_wsl, 64 ; q. hit max length?
jl get_line00 ; a. no .. get next character
get_line90: mov si, offset script_ws ; si -> work area
add si, script_wsl ; si -> next available character
mov word ptr [si], 0 ; move in null terminator
inc script_wsl ; save new length
stc ; set carry flag
get_line95: pop si ; restore register
ret ; ..and return to caller
get_line endp
; ----------------------------------------------------------------------
; comp_ul - uppercase a letter
;
; entry: al = a character
; exit: al = uppercase character
; ----------------------------------------------------------------------
comp_ul proc
cmp al, 'a' ; q. need uppercasing?
jl comp_ul1 ; a. no .. continue
cmp al, 'z' ; q. within range?
jg comp_ul1 ; a. no .. continue
and al, not 20h ; al = uppercase letter
comp_ul1: ret ; ..just return to caller
comp_ul endp
; ----------------------------------------------------------------------
; comp_copy - copy null terminated string and make into counted string
;
; entry: si -> target destination
; di -> string to copy
; exit: si -> next target buffer location
; ----------------------------------------------------------------------
comp_copy proc
push ax ; save registers
push bx
call string_len ; cx = string length
mov bx, si ; bx -> count byte
mov [si], cl ; store counted string byte
inc si ; si -> next compile buffer
xchg di, si ; get src and dest in order
or cx, cx ; q. zero length string?
jz comp_copy9 ; a. yes .. don't loop
comp_copy1: lodsb ; al = character from string
stosb ; store char @ destination
cmp al, 0 ; q. end of the line?
je comp_copy9 ; a. yes .. exit loop
cmp al, '^' ; q. control character?
jne comp_copy3 ; a. no .. continue
dec cx ; q. run out of string?
jz comp_copy9 ; a. yes .. exit here..
lodsb ; al = next character
cmp al, '^' ; q. need a carot?
je comp_copy2 ; a. yes .. then leave one out
call comp_ul ; ..and make uppercase
sub al, '@' ; al = control-@ to control-z
mov [di-1], al ; store over carot character
comp_copy2: dec byte ptr [bx] ; ..shorten counted string by one
comp_copy3: loop comp_copy1 ; ..and loop till end of string
comp_copy9: mov si, di ; si -> new dest in compile buffer
pop bx ; restore registers
pop ax
ret ; ..and return to caller
comp_copy endp
; ----------------------------------------------------------------------
; swap_psp - swap PSP and error handlers
; ----------------------------------------------------------------------
swap_psp proc
push bx ; save registers
push dx
push es
push ds
mov ah, 62h ; ah = get user's psp
int 21h ; call DOS
xchg bx, psp_seg ; bx = other psp
mov ah, 50h ; ah = setup psp address
int 21h ; call DOS
cmp tsr_active, 0 ; q. tsr pop'd up?
jne swap_psp10 ; a. yes .. continue
call swap_1b ; swap ^break handler in/out
swap_psp10: mov ax, 3523h ; ax = get ^C vector
int 21h ; call DOS
lds dx, dword ptr cs:user_i23 ; ds:dx = other handler
mov cs:user_i23, bx ; save old fields
mov cs:user_i23s, es ; ..and swap segment registers
mov ax, 2523h ; ax = setup interrupt vector
int 21h ; call DOS
mov ax, 3524h ; ax = get critical err vector
int 21h ; call DOS
lds dx, dword ptr cs:user_i24 ; ds:dx = other handler
mov cs:user_i24, bx ; save old fields
mov cs:user_i24s, es ; ..and swap segment registers
mov ax, 2524h ; ax = setup interrupt vector
int 21h ; call DOS
pop ds ; restore register
pop es
pop dx
pop bx
ret ; ..and return to caller
swap_psp endp
; ----------------------------------------------------------------------
; swap_1b - swap ^break handler
; ----------------------------------------------------------------------
swap_1b proc
push bx ; save registers
push ds
push es
mov ax, 351bh ; ax = get ^break vector
int 21h ; call DOS
lds dx, dword ptr cs:user_i1b ; ds:dx = other handler
mov cs:user_i1b, bx ; save old fields
mov cs:user_i1bs, es ; ..and swap segment registers
mov ax, 251bh ; ax = setup interrupt vector
int 21h ; call DOS
pop es ; restore registers
pop ds
pop bx
ret ; ..and return to caller
swap_1b endp
; ----------------------------------------------------------------------
; start - start backdown program
; ----------------------------------------------------------------------
start proc
cld ; clear direction flag!
mov sp, offset wstack ; ..
call cmd ; initialize the system
call get_buffers ; get i/o buffers
call script_init ; initialize script buffer
call scrinit ; clear screen buffer
; - get ready to go TSR
mov dx, nxtavail ; dx = high water area in bytes
shr dx, 1
shr dx, 1
shr dx, 1
shr dx, 1 ; dx = nbr of paragraphs
add dx, 16 ; ..and adjust for psp
mov ah, 4ah ; ah = set memory block size
mov es, psp_seg ; es -> our memory
mov bx, dx ; bx = nbr of paragraphs
int 21h ; issue DOS call
jnc start50 ; ..if ok, continue
xor al, al ; al = no help
mov dx, offset toosmall ; dx -> error message
call die ; ..and quit with message
start50: push dx ; save paragraphs needed
mov si, intblk1 ; si -> 1st interrupt block
mov cx, intblkcnt ; cx = nbr of ints handled
start60: mov ah, 35h ; ah = get interrupt vector
mov al, [si+12] ; al = interrupt number
int 21h ; .. get the current setting
mov [si+2], es ; save segment of old int
mov [si], bx ; .. and offset
mov dx, [si+13] ; dx -> new interrupt
mov ah, 25h ; ah = set interrupt vector
int 21h ; .. set up new vector
add si, intblklen ; si -> next entry
loop start60 ; .. set next interrupt
call io_init ; initialize the io port
cmp scriptfile, 0 ; q. run a script?
je start70 ; a. no .. continue
mov ah, 9 ; ah = display message
lea dx, tsrsetup ; dx -> script will run msg
int 21h ; issue DOS msg
start70: lea dx, installed ; dx -> installed ok
mov ah, 9 ; ah = say ok
int 21h ; .. display message
mov byte ptr dollar, 0 ; change $ to null termination
mov byte ptr hdrmsg_1, ' ' ; change <lf> to blank
lea si, hdrmsg ; dx -> header/copyright msg
call disp_msg ; display on TSR's screen
lea si, bd_help$ ; dx -> help message
call disp_msg ; display on TSR's screen
dec main_active ; let main run now
mov ax, 3100h ; ax = be TSR, w/rc = 0
pop dx ; restore para's needed
int 21h ; .. now hope & pray
start endp
; ----------------------------------------------------------------------
; scrinit - initiailize tsr screen buffer
; ----------------------------------------------------------------------
scrinit proc
push ax ; save registers
push cx
push di
push es
mov ah, 0fh ; get current display mode
int 10h ; .. ask BIOS
cmp al, 3 ; q. Color mode?
jne scrinit10 ; a. No .. leave in mono
mov ourattr, colattr ; else .. assume color attr
scrinit10: mov ax, 4000 ; ax = size of screen buffer
call getmem ; get some memory
mov disp_bufseg, ax ; save segment of buffer
mov es, ax ; es = screen buffer segment
xor di, di ; di = offset of zero
mov ah, ourattr ; ah = attribute to use
mov al, ' ' ; al = blank character
mov cx, 25 * 80 ; .. words to move
scrinit20: stosw ; save a char & attribute
loop scrinit20 ; .. until all moved
pop es ; restore regs
pop di
pop cx
pop ax
ret ; return to caller
scrinit endp
; ----------------------------------------------------------------------
; getmem - get some TSR memory
;
; entry: ax = bytes of request
;
; exit: ax = segment of available memory
; bx = offset from DS of available memory
; ----------------------------------------------------------------------
getmem proc
push dx ; save register
mov bx, nxtavail ; bx = offset of avail memory
add ax, 15 ; ax = request full paragraphs
and ax, 0fff0h ; ax = even paragraph amt
add nxtavail, ax ; update next available offset
mov ax, bx ; ax = current offset
shr ax, 1 ; convert byte offset to para's
shr ax, 1
shr ax, 1
shr ax, 1
mov dx, ds ; dx = our segment
add ax, dx ; ax = absolute seg of new memory
pop dx ; restore register
ret ; ..and return to caller
getmem endp
; ----------------------------------------------------------------------
; get_buffers - get i/o buffers and protocol overlay area
; ----------------------------------------------------------------------
get_buffers proc
mov ax, send_equsiz ; ax = size of send in para's
call getmem ; allocate some memory
mov send_bufseg, ax ; save segment for later
mov ax, bdplen ; ax = size of largest .BDP file
call getmem ; allocate some memory
mov word ptr bd_proto+2, ax ; save segment address
mov bd_offset, bx ; ..and offset too
mov ax, rcv_equsiz ; ax = size of rcv in para's
call getmem ; allocate some memory
mov rcv_bufseg, ax ; save segment for later
ret ; ..and return to caller
get_buffers endp
; ----------------------------------------------------------------------
; script_init - initialize script buffer
; ----------------------------------------------------------------------
script_init proc
mov ax, script_amt ; ax = para's for script buf
add ax, 15 ; .. correct for boundary
call getmem ; get the memory
mov script_buf, bx ; save script buffer offset
ret
script_init endp
; ----------------------------------------------------------------------
; stack area, which will grow back over above routines
; ----------------------------------------------------------------------
even
db 20 dup ('STACK') ; our stack
wstack dw 0
; **********************************************************************
align 16 ; align to a paragraph
mem_end = $ ; end of code
; memory after this point is
; overlayed when we go TSR
; **********************************************************************
; ----------------------------------------------------------------------
; protocol header structures
; ----------------------------------------------------------------------
bdmaxprots = 10 ; number of protocols supported
bdprotn dw 0 ; protocols found
bdprot1 label byte
rept bdmaxprots ; protocol headers
bdprot <>
endm
bdpath db 65 dup (0) ; path for BPD files
bdplen dw 0 ; longest .BDP found
; ----------------------------------------------------------------------
; Non-TSR messages
; ----------------------------------------------------------------------
installed db "Backdown installed successfully",13,10,"$"
hdrmsg db "BD ", VERSN, " ■ Copyright (c) 1992, Bob Flanders"
db " and Michael Holmes"
hdrmsg_1 db 10
db 13, "Backdown first appeared in PC Magazine, "
db "May 12, 1992", 10
crlf$ db 13,10
dollar db "$",0
help db " BackDown, the background download utility"
db 13,10,10,"Usage:",13,10,10
db "BD [/Pn|/Hxxx,i] /C /Szz /T /U script {operands}"
db 13,10,10
db "where /Pn is the COMn port",13,10
db " /Hxxx,i is the port addr, interrupt"
db " for non-standard COM ports",13,10
db " /C compiles a script",13,10
db " /Szz is the max script size in bytes",13,10
db " /T tests for TSR resident and/or busy",13,10
db " /U uninstalls the TSR",13,10
db " script is the script filename",13,10
db " operands are passed when the script executes",13,10
db 13,10,"$"
dosmsg db "Must be DOS 3.1 or higher",13,10,"$"
protsavail db "Protocols available ..$"
protsetup db 13,10," $"
noport db "COM port not present or responding",13,10,"$"
readymsg db "Backdown is resident and not busy",13,10,"$"
busymsg db "Backdown is resident but busy",13,10,"$"
notup db "Backdown not resident",13,10,"$"
tsrsetup db "TSR will start script",13,10,"$"
tsrbusy db "TSR too busy to start a script",13,10,"$"
toosmall db "Not enough memory to run",13,10,"$"
invopnd db "Invalid operand for "
invopnc db " ",13,10,"$"
badopnd db "Invalid operand",13,10,"$"
upalrdy db "Already installed",13,10,"$"
cantfree db "Can't uninstall at this time",13,10,"$"
freeok db "Uninstalled successfully",13,10,"$"
uninscan db "Uninstall cancelled. BACKDOWN still resident.",13,10,"$"
done db 13,10,"Script finished",13,10,"$"
waitmsg db "Download still active ..",13,10
db " hit ESC to leave BD resident",13,10
db " any other key to force uninstall",13,10,10,"$"
needfile db "Script filename missing or not found",13,10,"$"
compdone db "Compile completed sucessfully, compiled file is$"
compamt db " bytes long",13,10,"$"
badcmd db ">> Bad command letter",13,10,"$"
nolabel db ">> No label for GOTO command",13,10,"$"
undefined db ">> Undefined label for GOTOs",13,10,"$"
undef_msg db " "
undef_item db 12 dup (0)
tablefull db ">> No room for additional labels or references",13,10,"$"
badvariable db ">> Bad prompt variable letter (A-Z)",13,10,"$"
lab_missing db ">> Label name missing",13,10,"$"
duplabel db ">> Label already used",13,10,"$"
wontopen db ">> Cannot open compiled output file",13,10,"$"
cantwrite db ">> Error writing output file",13,10,"$"
missingmsg db ">> Missing text in following command",13,10,"$"
badtype db ">> Bad operand value",13,10,"$"
; ----------------------------------------------------------------------
; Initialization time constants and work areas
; ----------------------------------------------------------------------
io_table dw 3f8h ; i/o address - COM1
db 4 ; & interrupt
dw 2f8h ; - COM2
db 3
dw 3e8h ; - COM3
db 4
dw 2e8h ; - COM4
db 3
cmd_line db 127 dup (0) ; temporary cmd line
; ----------------------------------------------------------------------
; find protocol modules work area
; ----------------------------------------------------------------------
bdpenvar db "BDP=" ; variable to look for
bdpfiles db "*.BDP", 0 ; files to look for
bdpwrk db 65 dup (0) ; work area for lookup/read
bdpdta db 128 dup (?) ; work DTA
; ----------------------------------------------------------------------
; script compiler work areas
; ----------------------------------------------------------------------
compile_flg db 0 ; compile wanted switch
scr_handle dw 0 ; file handle for script input
line_size db 0 ; length of last line read
line_buffer db 100 dup (0) ; line buffer
line_end = $ ; line buffer end
bds db ".BDS",0 ; input file extension
eof db 0 ; eof flag
comp_cmds db 'O', 1 ; options and init port
dw comp_init
db 'S', 2 ; send string
dw comp_send
db 'N', 3 ; notify operator
dw comp_send
db 'R', 4 ; wait for reply
dw comp_send
db 'T', 5 ; set timeout
dw comp_time
db 'H', 6 ; hangup
dw comp_hang
db 'D', 7 ; download file
dw comp_down
db 'P', 8 ; prompt for variable
dw comp_what
db 'W', 9 ; wait
dw comp_wait
db 'G', 10 ; goto label
dw comp_goto
db ':', 0 ; label declaration
dw comp_label
db ';', 0 ; comment line
dw comp_nada
db 'E', 15 ; echo options
dw comp_opt
db '=', 16 ; equate
dw comp_what
db 0 ; end of list marker
comp_parms db "300",0,0,0, 0, 0, 384/2 ; baud rates
db "1200",0,0, 0, 0, 96/2
db "2400",0,0, 0, 0, 48/2
db "9600",0,0, 0, 0, 12/2
db "8N1",0,0,0, 0, 1, lcr_N81 ; line control array
db "7E1",0,0,0, 0, 1, lcr_E71
db "7O1",0,0,0, 0, 1, lcr_O71
db "7BIT",0,0, 0, 2, 2 ; 7 and 8 bit toggle
db "8BIT",0,0, 0, 2, 1
db "B+",0,0,0,0,0, 3, 2 ; B+ toggle
db "B-",0,0,0,0,0, 3, 1
db "CASE",0,0, 0, 4, 1 ; case control
db "NOCASE", 0, 4, 2
comp_parme = $
comp_parml = 9 ; length of one entry
comp_parmn = (comp_parme - comp_parms) / comp_parml
sym_name equ byte ptr 0 ; null ended symbol string
sym_flag equ byte ptr 9 ; flag: 0 = unused
; 1 = reference
; 2 = resolved
sym_offset equ word ptr 10 ; offset into table
sym_entry = 12 ; length of one entry
sym_number = 50 ; number of symbol entries
sym_size = sym_entry * sym_number ; size of symbol table
symbols db sym_size dup (0) ; symbol table
compile_ptr dw compile_buf ; where to put next cmd
; ----------------------------------------------------------------------
; cmd - initialize and process command line
;
; entry: cs -> our segment
; ----------------------------------------------------------------------
cmd proc ; find/process command
mov cs:psp_seg, ds ; save addr of our psp
mov ax, cs ; ax = our segment
mov es, ax ; .. and es
mov si, 81h ; ds:si -> command line
mov di, offset cmd_line ; es:di -> local cmd line
mov cx, 127 ; cx = max length
rep movsb ; ..and move locally
mov ds, ax ; ds -> our segment too
mov user_i23s, ax ; save our segment
mov user_i24s, ax ; ..
mov user_i1bs, ax ; ..
mov dx, offset hdrmsg ; ds:dx -> header message
mov ah, 9 ; ah = print ASCII$ string
int 21h ; .. display header
mov ah, 30h ; ah = get version nbr
int 21h ; call DOS
cmp al, 3 ; q. DOS 3.0 or higher?
jb cmd_1 ; a. no .. give error msg
ja cmd_2 ; else .. greater than 3.x
or ah, ah ; q. 3.0?
jnz cmd_2 ; a. no .. 3.1 or better
cmd_1: mov dx, offset dosmsg ; dx -> must be >= DOS 3.1
xor al, al ; al = no help for them
call die ; give msg and die
cmd_2: call loaded ; check if loaded
mov tsr_loaded, di ; save load addr, if loaded
mov si, offset cmd_line ; si -> command line
call upcase ; upcase the command line
cmd00: call nxtop ; q. any operands left?
jnc cmd05 ; a. yes .. continue
call init ; do initialization
ret ; return to caller
cmd05: cmp word ptr [si], '?/' ; q. help request?
jnz cmd07 ; a. yes .. give some help
mov dx, offset dollar ; dx -> null message
mov al, 1 ; al = give help
call die ; terminal w/help
cmd07: cmp word ptr [si], 'P/' ; q. port number?
jnz cmd20 ; a. no .. check next
mov al, [si + 2] ; al = port nbr in ASCII
cmp al, '1' ; q. less than COM1?
jl cmd10 ; a. yes .. give error message
cmp al, '4' ; q. greater than COM4?
jg cmd10 ; a. yes .. give error message
sub al, '0' ; al = COMn number
cbw ; ax = COMn number
mov io_base, ax ; save for later
add si, 3 ; si -> after this operand
jmp short cmd00 ; ..continue w/next operand
cmd10: mov word ptr invopnc, 'P/' ; move /P into message
mov dx, offset invopnd ; dx -> error message
xor al, al ; al = no help
call die ; ..give error message
cmd20: cmp word ptr [si], 'H/' ; q. hex port addr
jnz cmd30 ; a. no .. check next
add si, 2 ; si -> hex address
call htoi ; ax = hex port addr
cmp ax, 100h ; q. less than reasonable?
jl cmd25 ; a. yes .. give error message
cmp ax, 400h ; q. greater than reasonable?
jg cmd25 ; a. yes .. give error message
mov io_base, ax ; save port addr for later
cmp byte ptr [si], ',' ; q. proper format?
jne cmd25 ; a. no .. give error message
inc si ; si -> next char in cmd line
call atoi ; al = interrupt nbr
cmp ax, 2 ; q. less than reasonable?
jl cmd25 ; a. yes .. give error message
cmp ax, 15 ; q. greater than reasonable?
jg cmd25 ; a. yes .. give error message
mov io_int, al ; save interrupt nbr for latter
jmp short cmd00 ; ..continue w/next operand
cmd25: mov word ptr invopnc, 'H/' ; move /H into message
mov dx, offset invopnd ; dx -> error message
xor al, al ; al = no help
call die ; ..give error message
cmd30: cmp word ptr [si], 'U/' ; q. uninstall?
jne cmd40 ; a. no .. continue
jmp uninstall ; else .. jump into uninstall
cmd40: cmp word ptr [si], 'C/' ; q. compile?
jne cmd45 ; a. no .. continue
add si, 2 ; si -> next operand
mov byte ptr compile_flg, 1 ; set compile flag
jmp cmd00 ; ..then get next token
cmd45: cmp word ptr [si], 'T/' ; q. test if script running?
jne cmd50 ; a. no .. continue
xor al, al ; al = no help
cmp tsr_loaded, 0 ; q. loaded at all?
jne cmd46 ; a. yes .. continue
mov dx, offset notup ; dx -> not here message
mov dos_rc, 2 ; set errorlevel
call die ; ..and exit w/message
cmd46: call needwait ; q. just waiting around?
jc cmd47 ; a. no .. give right msg
mov dx, offset readymsg ; dx -> not busy message
mov dos_rc, 0 ; set errorlevel
call die ; ..give msg and quit
cmd47: mov dx, offset busymsg ; dx -> doing something
call die ; ..give msg and quit too
cmd50: cmp word ptr [si], 'S/' ; q. set script buffer size?
jne cmd60 ; a. no .. continue
add si, 2 ; si -> next operand
call atoi ; ax = buffer size
cmp ax, 150 ; q. less than reasonable?
jb cmd55 ; a. yes .. give error message
cmp ax, 32000 ; q. greater than reasonable?
ja cmd55 ; a. yes .. give error message
mov script_amt, ax ; save amount for later
jmp cmd00 ; ..then get next token
cmd55: mov word ptr invopnc, 'S/' ; move /S into message
mov dx, offset invopnd ; dx -> error message
xor al, al ; al = no help
call die ; ..give error message
cmd60: cmp byte ptr scriptfile, 0 ; q. filename already given?
jz cmd70 ; a. no .. continue
mov dx, offset badopnd ; dx -> error message
xor al, al ; al = no help
call die ; ..give error message
cmd70: mov cx, scriptf_len ; cx = max string size
mov di, offset scriptfile ; di -> destination area
mov script_isi, di ; save addr of string
mov main_state, 4 ; ..and setup for script
call token_copy ; copy next token
jmp cmd00 ; then loop up for next operand
cmd endp ; end of scan routine
; ----------------------------------------------------------------------
; token_copy - copy blank delimited token
;
; entry: si -> source
; di -> destination
; cx = max length
; ----------------------------------------------------------------------
token_copy proc
lodsb ; al = character from string
cmp al, ' ' ; q. end of the line?
jge token_c10 ; a. no .. continue
dec si ; si -> null character
ret ; ..then return to caller
token_c10: stosb ; store char @ destination
loop token_copy ; ..and loop till end
token_c90: ret ; ..and return
token_copy endp
; ----------------------------------------------------------------------
; upcase - upcase string
;
; entry: si -> source
; ----------------------------------------------------------------------
upcase proc
push ax ; save registers
push si
push di
mov di, si ; di -> dest, same as source
upcase10: lodsb ; al = character from string
cmp al, 0 ; q. end of the line?
je upcase90 ; a. yes .. exit loop
cmp al, 0dh ; q. end of the line?
je upcase90 ; a. yes .. exit loop
cmp al, 'a' ; q. already upper case?
jl upcase20 ; a. yes .. continue
and al, not 20h ; al = upper case letter
upcase20: stosb ; store char @ destination
jmp short upcase10 ; ..and loop till end of string
upcase90: mov byte ptr [di], 0 ; mark end of string
pop di ; restore registers
pop si
pop ax
ret ; ..and return
upcase endp
; ----------------------------------------------------------------------
; atoi - character to integer
;
; entry: si -> string
;
; exit: ax = number
; si -> 1st non-numeric character
; ----------------------------------------------------------------------
atoi proc
push bx ; save registers
push cx
push dx
xor ax, ax ; ax = zero for accumulation
xor bh, bh ; bh = zero for addition
mov cx, 10 ; cx = multiplier
atoi10: mov bl, [si] ; bl = character from string
cmp bl, '0' ; q. less than a zero?
jl atoi90 ; a. yes .. done
cmp bl, '9' ; q. greater than a nine?
jg atoi90 ; a. yes .. done here too
sub bl, '0' ; bl = ATOI of character
mul cx ; ax = ax * 10
add ax, bx ; ax = new accumulator
inc si ; si -> next string character
jmp short atoi10 ; ..then loop till end of string
atoi90: pop dx ; restore registers
pop cx
pop bx
ret ; ..and return to caller
atoi endp
; ----------------------------------------------------------------------
; htoi - hex character to integer
;
; entry: si -> string
;
; exit: ax = number
; si -> 1st non-numeric character
; ----------------------------------------------------------------------
htoi proc
push cx ; save registers
xor ax, ax ; ax = zero for accumulation
htoi10: mov ch, [si] ; cl = character from string
cmp ch, '0' ; q. less than a zero?
jl htoi90 ; a. yes .. done
cmp ch, '9' ; q. greater than a nine?
jg htoi20 ; a. yes .. done here too
sub ch, '0' ; ch = ATOI of character
jmp short htoi30 ; ..continue w/common code
htoi20: cmp ch, 'A' ; q. less than an ah?
jl htoi90 ; a. yes .. done here
cmp ch, 'F' ; q. greater than an ef?
jl htoi90 ; a. yes .. done here too
sub ch, 'A' - 10 ; ch = HTOI of character
htoi30: mov cl, 4 ; ch = shift factor
shl ax, cl ; ax = ax << 4
or al, ch ; ax = new accumulator
inc si ; si -> next char from string
jmp short htoi10 ; ..then loop till end of string
htoi90: pop cx ; restore registers
ret ; ..and return to caller
htoi endp
; ----------------------------------------------------------------------
; loaded - check if TSR loaded
;
; exit: di = 0 or segment of TSR
; ----------------------------------------------------------------------
loaded proc
xor di, di ; di = initially TSR not avail
mov ax, multiplex ; ax = multiplex identifier
int 2fh ; issue multiplex interrupt
ret
loaded endp
; ----------------------------------------------------------------------
; nxtop - find next operand
;
; entry: si -> current position
;
; exit: si -> 1st non-blank character
; carry = end of line
; ----------------------------------------------------------------------
nxtop proc
cmp byte ptr [si], 0 ; q. end of line?
jne nxtop10 ; a. no .. continue
stc ; show end of line condition
ret ; ..and return to caller
nxtop10: cmp byte ptr [si], ' ' ; q. whitespace?
jna nxtop20 ; a. yes .. skip whitespace
clc ; show operand found
ret ; ..and return to caller
nxtop20: inc si ; si -> next char
jmp short nxtop ; ..loop to find nxt operand
nxtop endp
; ----------------------------------------------------------------
; init - operands are parsed, now process the command line
; ----------------------------------------------------------------
init proc
cmp compile_flg, 0 ; q. need compile?
je init05 ; a. no .. continue
jmp compile ; else .. do it
init05: cmp tsr_loaded, 0 ; q. already loaded?
je init10 ; a. no .. ok to load
cmp scriptfile, 0 ; q. run a script?
je init08 ; a. no .. continue
push es ; save register
mov es, tsr_loaded ; es -> loaded copy
cmp es:main_state, 0 ; q. terminal mode?
pop es ; ..restore register
je init07 ; a. yes .. continue
xor al, al ; al = no help
mov dx, offset tsrbusy ; dx -> error msg
call die ; ..issue msg and die
init07: mov di, offset scriptfile ; di -> cmd line script name
call string_len ; cx = string length
mov es, tsr_loaded ; es -> loaded copy of BD
mov es:script_isi, di ; save addr of string
mov si, di ; si -> non-tsr script name
call string_copy ; copy to tsr
mov es:main_state, 4 ; ..and setup for script
xor al, al ; al = no help needed
mov dx, offset tsrsetup ; dx -> compl msg
call die ; ..give msg and die
init08: xor al, al ; al = no help needed
mov dx, offset upalrdy ; dx -> up already message
call die ; .. die .. with honor
init10: push es ; save es
mov ah, 34h ; ah = get DOS busy flg addr
int 21h ; call DOS
dec bx ; bx -> InDos Flags
mov word ptr dos_busy, bx ; save offset
mov word ptr dos_busy+2, es ; ..and segment of busy flag
pop es ;
mov ax, io_base ; ax = comm base addr
cmp ax, 4 ; q. COMn specified?
jg init20 ; a. no .. continue
dec ax ; al = zero based entry nbr
mov cl, 3 ; cl = entry size
mul cl ; ax = table offset
mov bx, ax ; bx = same
mov ax, io_table[bx] ; ax = base address
mov io_base, ax ; ..save for later
mov al, byte ptr io_table+2[bx] ; al = interrupt number
mov io_int, al ; ..save for later
init20: mov al, io_int ; al = interrupt to attach
add al, 8 ; al = hardware vector nbr
mov hd_int, al ; save in interrupt table
mov dx, iir ; dx = interrupt id register
call in_reg ; al = iir if UART present
test al, 0f8h ; q. UART present?
jz init30 ; a. yes .. continue
xor al, al ; al = no help
mov dx, offset noport ; dx -> no port message
call die ; give message and exit
init30: call bdenv ; find BDP= environment
ret ; return to caller
init endp
; ----------------------------------------------------------------------
; uninstall - process the uninstall request
; ----------------------------------------------------------------------
uninstall proc
cmp tsr_loaded, 0 ; q. tsr loaded?
jne unins05 ; a. yes .. continue
xor ax, ax ; ax = zero, no extra help
mov dx, offset notup ; dx -> message
jmp die ; .. die now, sucker
unins05: call needwait ; q. need to wait?
jnc unins09 ; a. no .. continue
lea dx, waitmsg ; dx -> wait message
mov ah, 9 ; ah = print ASCII$ message
int 21h ; print message
unins08: call needwait ; q. need to wait more?
jnc unins09 ; a. no .. continue
mov ah, 0bh ; ah = check keyboard status
int 21h ; call DOS
cmp al, 0ffh ; q. character waiting?
jne unins08 ; a. no .. continue waiting
mov ah, 08h ; ah = get char
int 21h ; al = char
cmp al, 1bh ; q. escape?
jne unins09 ; a. no .. continu
mov dx, offset uninscan ; dx -> cancelled message
jmp short unins90 ; .. and finish now
unins09: mov si, tsr_loaded ; si -> tsr's memory
mov ds, si ; ds -> same
mov es, si ; es -> same
call io_reset ; turn off UART's interrupts
mov di, intblk1 ; bx -> first interrupt blk
mov cx, intblkcnt ; cx = number of ints used
unins10: mov ah, 35h ; ah = get interrupt
mov al, [di+12] ; al = interrupt number
int 21h ; es:bx -> interrupt
mov ax, es ; ax = int segment
cmp ax, si ; q. our segment?
jne unins80 ; a. no .. can't uninstall
add di, intblklen ; si -> next block
loop unins10 ; .. check next block
mov di, intblk1 ; si -> first interrupt blk
mov cx, intblkcnt ; cx = number of ints used
cli ; no ints ..
unins20: lds dx, dword ptr es:[di] ; ds:dx -> old interrupt rtn
mov ah, 25h ; ah = set interrupt
mov al, es:[di+12] ; al = int to set
int 21h ; .. set the interrupt
add di, intblklen ; si -> next block
loop unins20 ; .. reset next interrupt
sti ; .. allow interrupts again
mov es, es:psp_seg ; es = tsr's psp
mov ah, 49h ; ah = free tsr memory
int 21h ; .. do it
mov dx, offset freeok ; dx -> freed ok.
jmp short unins90 ; .. end the job, painlessly
unins80: mov dx, offset cantfree ; dx -> can't free message
unins90: xor al, al ; al = no help
push cs ; restore our ..
pop ds ; ..own segment
call die ; die .. hard & fast
uninstall endp
; ----------------------------------------------------------------------
; needwait - checks for the need to wait while download finishes
;
; exit: carry = wait needed
; ----------------------------------------------------------------------
needwait proc
push es ; save register
mov es, tsr_loaded ; es -> tsr's data segment
cmp es:main_state, 0 ; q. just waiting around?
pop es ; ..restore register
je needwait1 ; a. yes .. continue
stc ; set carry / wait
ret ; ..then return to caller
needwait1: clc ; clear carry / no-wait
ret ; ..then return to caller
needwait endp
; ----------------------------------------------------------------------
; die - terminate w/optional help message
;
; entry: dx -> intermediate message
; al = not zero if help wanted
; ----------------------------------------------------------------------
die proc
push ax ; save help request
mov ah, 9 ; ah = print ASCII$ message
int 21h ; print the error message
pop ax ; restore help request
or al, al ; q. help wanted?
jz die10 ; a. no .. exit
mov dx, offset help ; dx -> help message
mov ah, 9 ; ah = print ASCII$ message
int 21h ; ... print the help
die10: mov ah, 4ch ; ah = exit to DOS
mov al, dos_rc ; al = return code
int 21h ; ..return to dos
die endp
; ----------------------------------------------------------------------
; Find BDP environment variable, move path local
; ----------------------------------------------------------------------
bdenv proc near
push es ; save registers
push ds
mov ds, psp_seg ; ds -> psp segment
mov ds, ds:[002ch] ; ds -> environment
push cs ; save our segment
pop es ; es -> our segment
cld ; direction is up
xor si,si ; di -> start of environment
bdenv10: push si ; save current env offset
mov di, offset bdpenvar ; di -> variable to look for
mov cx, 4 ; length of string
repe cmpsb ; q. same string?
je bdenv50 ; a. yes .. move in path
pop si ; si -> start of env var
bdenv20: lodsb ; al = char
or al, al ; q. end of string?
jnz bdenv20 ; a. no .. get next byte
cmp byte ptr [si], 0 ; q. end of enviroment?
jne bdenv10 ; a. no .. check next var
jmp short bdenv90 ; else .. not found, exit
bdenv50: pop ax ; kill pushed address
mov di, offset bdpath ; di -> path variable
bdenv60: lodsb ; al = char from env
stosb ; .. put in path
or al, al ; q. end of var?
jnz bdenv60 ; a. no .. get next char
bdenv90: pop ds ; ds -> our segment
mov es, psp_seg ; es -> psp segment
mov es, es:[002ch] ; es -> environment
mov ah, 49h ; ax = release it
int 21h ; .. tell dos to make it so
pop es ; restore regs
call bdpsch ; search for .BDP files
ret ; return to caller
bdenv endp
; ----------------------------------------------------------------------
; bdpbld - build .BDP path/filename
;
; entry: es:di -> fully qualified (FQ) file name area
; ds:si -> ASCIIZ name to append
;
; exit: di -> ASCIIZ FQ file name
; ----------------------------------------------------------------------
bdpbld proc ; build file name
push di ; save pointer
push si ; save append name
mov si, offset bdpath ; si -> path to move
bdpbld10: cmp byte ptr [si], 0 ; q. end of path?
je bdpbld20 ; a. yes .. append name
movsb ; move a byte
jmp bdpbld10 ; .. check next byte
bdpbld20: pop si ; si -> name to move
bdpbld30: movsb ; move a byte of name
cmp byte ptr [si-1], 0 ; q. last byte zero?
jne bdpbld30 ; a. no .. move another
pop di ; restore ptr
ret ; return to caller
bdpbld endp
; ----------------------------------------------------------------------
; bdpsch - search for .BDP modules
; ----------------------------------------------------------------------
bdpsch proc
mov dx, offset bdpdta ; ds:dx -> new DTA
mov ah, 1ah ; ah = set new DTA fnc
int 21h ; .. tell DOS to do it
cmp bdpath, 0 ; q. any environment set?
jne bdpsch10 ; a. yes .. use it
mov ah, 19h ; ah = get default drive
int 21h ; al = default drive
add al, 'A' ; .. change to a letter
mov bdpath, al ; set the drive
mov bdpath+1, ':' ; .. with colon
mov bdpath+2, '\' ; .. and root dir
mov si, offset bdpath+3 ; si -> place to put path
xor dl, dl ; dl = current drive
mov ah, 47h ; ah = get current dir
int 21h ; .. read in current dir
bdpsch10: mov di, offset bdpath ; di -> bdp directory
xor al, al ; al = look for zero
mov cx, 65 ; cx = max 65 chars
cld ; .. in upward direction
repne scasb ; scan for the end
cmp byte ptr [di-2], '\' ; q. end in backslash?
je bdpsch15 ; a. yes .. continue
mov byte ptr [di-1], '\' ; else .. force ending
mov byte ptr [di], 0 ; .. in backslash
bdpsch15: mov di, offset bdpwrk ; di -> work area
mov si, offset bdpfiles ; si -> file names
call bdpbld ; .. build search environment
mov dx, di ; dx -> search argument
lea di, bdprot1 ; di -> 1st entry
xor cx, cx ; cx = no attributes
mov ah, 4eh ; ah = find first
bdpsch20: int 21h ; q. file found?
jc bdpsch70 ; a. no .. exit
cmp word ptr bdpdta.fiSize+2, 0 ; q. valid file size?
jne bdpsch30 ; a. no check next
cmp bdprotn, 0 ; q. 1st protocol?
jne bdpsch25 ; a. no .. skip message
mov ah, 9 ; ah = print message
lea dx, protsavail ; dx -> available protocols msg
int 21h ; issue DOS call
bdpsch25: call bdpgetinfo ; get the file information
cmp bdprotn, bdmaxprots ; q. all protocols filled?
je bdpsch70 ; a. yes .. look no further
bdpsch30: mov ah, 4fh ; ah = find next file
jmp bdpsch20 ; .. ask DOS about it
bdpsch70: mov dx, 80h ; dx -> original dta
mov ah, 1ah ; ah = setup new dta
int 21h ; .. tell DOS to do it
add di, 15 ; di = rounding up..
and di, 0fff0h ; ..to next paragraph
mov nxtavail, di ; start alloc's after hdrs
cmp bdprotn, 0 ; q. any protocols?
je bdpsch80 ; a. no .. give warning msg
mov ah, 9 ; ah = display message
lea dx, crlf$ ; dx -> spacing message
int 21h ; issue DOS call
int 21h ; ..again
jmp short bdpsch90 ; ..and exit thru bottom
bdpsch80: mov ah, 9 ; ah = display a message
lea dx, noprots ; dx -> no protocols avail
int 21h ; issue DOS call
mov noprots_1, 0 ; make null terminated string
bdpsch90: ret ; return to caller
bdpsch endp
; ----------------------------------------------------------------------
; bdpgetinfo - get .BDP file header information
;
; entry: di -> table entry to fill in
; exit: di -> next available entry
; ----------------------------------------------------------------------
bdpgetinfo proc ; get information on protocol
push di ; save bdprot pointer
lea di, [di].bdpfile ; di -> prot file name area
lea si, bdpdta.fiName ; si -> protocol file name
call bdpbld ; .. build FQ file name
mov dx, di ; ds:dx -> file name
pop di ; .. restore prot pointer
mov ax, 3d00h ; ax = open for read
int 21h ; open the file
jc bdpget90 ; .. exit if error
push ax ; save the handle
mov bx, ax ; bx = handle
mov ah, 3fh ; ah = read
mov cx, 6 ; ..JMP through protocol count
lea dx, bdpwrk ; dx -> into the work area
int 21h ; read the header
jc bdpget80 ; ..skip file if error
mov ax, word ptr bdpwrk+3 ; get the "BD"
cmp ax, "DB" ; q. backdown module?
jne bdpget80 ; a. no .. skip this file
mov cl, bdpwrk+5 ; cl = protocols in this module
xor ch, ch ; cx = loop counter
bdpget10: push cx ; save loop counter
mov ah, 3fh ; ah = read
mov cx, 19 ; cx = bytes to move
mov dx, di ; dx = di = header area
int 21h ; read the header
lea di, [di].bdpfile ; di -> prot file name area
lea si, bdpdta.fiName ; si -> protocol file name
call bdpbld ; build FQ file name
mov di, dx ; di -> start of entry again
mov ah, 9 ; ah = display message
lea dx, protsetup ; dx -> spacing message
int 21h ; issue DOS call
push bx ; save registers
mov bx, 1 ; bx = STDOUT handle
mov cx, 17 ; cx = chars to write
lea dx, [di+1] ; dx -> protocol description
mov ah, 40h ; ah = write to file
int 21h ; .. do it DOS
pop bx ; restore registers
pop cx ;
inc bdprotn ; increment num of protocols
cmp bdprotn, bdmaxprots ; q. all protocols filled?
je bdpget80 ; a. yes .. look no further
add di, bdprotlen ; di -> next table entry
loop bdpget10 ; loop till table filled
mov ax, word ptr bdpdta.fiSize ; ax = size of file
cmp ax, bdplen ; q. bigger than largest so far?
jna bdpget80 ; a. no .. check next
mov bdplen, ax ; .. set new len
bdpget80: pop bx ; bx = handle to close
mov ah, 3eh ; ah = close function
int 21h ; .. do it DOS
bdpget90: ret ; return to caller
bdpgetinfo endp
; ----------------------------------------------------------------------
; compile - script compiler
; ----------------------------------------------------------------------
compile proc
call comp_open ; open script file
comp10: call comp_read ; read a line
jc comp50 ; at eof, cleanup
call comp_pars ; parse line into buffer
jmp short comp10 ; ..and loop till eof
comp50: call comp_check ; check for unresolved references
call comp_write ; write out compiled file
call comp_stats ; give completion msg and die
compile endp
; ----------------------------------------------------------------------
; comp_open - open script file
;
; entry: scriptfile = filename
;
; exit: scr_handle = file handle
; ----------------------------------------------------------------------
comp_open proc
cmp scriptfile, 0 ; q. script filename given?
je comp_open3 ; a. yes .. continue
comp_open1: mov di, offset scriptfile ; di -> script filename
mov al, '.' ; al = search character
call string_len ; cx = string length
repne scasb ; q. find the period?
je comp_open2 ; a. yes .. continue
mov si, offset bds ; si -> script extension
call string_copy ; copy our extension
comp_open2: mov dx, offset scriptfile ; dx -> filename
mov ax, 3d00h ; ax = open for read function
int 21h ; call DOS
jnc comp_open4 ; ..if ok, continue
comp_open3: mov dx, offset needfile ; dx -> error message
xor ax, ax ; ax = give msg only
call die ; ..give 'em some help
comp_open4: mov scr_handle, ax ; save file handle for later
ret ; ..and return
comp_open endp
; ----------------------------------------------------------------------
; comp_read - read a script line
;
; exit: line_buffer = inputted line
; ----------------------------------------------------------------------
comp_read proc
cmp eof, 1 ; q. at eof, already?
je comp_rea9 ; a. no .. continue
comp_rea0: mov bx, scr_handle ; bx = handle number
mov cx, 1 ; cx = nbr of chars to read
mov dx, offset line_buffer ; dx -> input buffer
comp_rea1: mov ah, 3fh ; ah = read function code
int 21h ; call DOS
or ax, ax ; q. anything read?
jz comp_rea7 ; a. no .. must be at eof
mov si, dx ; si -> last character read
cmp byte ptr [si], ' ' ; q. less than a blank?
jle comp_rea1 ; a. yes .. get next character
inc dx ; dx -> next buffer spot
comp_rea2: mov ah, 3fh ; ah = read function code
int 21h ; call DOS
or ax, ax ; q. anything read?
jz comp_rea7 ; a. no .. must be at eof
mov si, dx ; si -> last character read
cmp byte ptr [si], 0dh ; q. carriage return?
je comp_rea3 ; a. yes .. exit loop
inc dx ; dx -> next buffer spot
cmp dx, offset line_end ; q. at end of input buffer?
jl comp_rea2 ; a. no .. loop
comp_rea3: mov si, dx ; si -> next line buffer position
mov word ptr [si], 0 ; make into null terminated string
jmp short comp_rea8 ; ..and test if ok to leave
comp_rea7: mov eof, 1 ; show input at eof
comp_rea8: cmp dx, offset line_buffer ; q. anything read?
je comp_rea9 ; a. no .. return eof
mov next_token, offset line_buffer + 1 ; init token pointer
clc ; show everything is ok
ret ; ..and return to caller
comp_rea9: stc ; show at eof
ret ; ..and return to caller
comp_read endp
; ----------------------------------------------------------------------
; comp_pars - parse script command
; ----------------------------------------------------------------------
comp_pars proc
mov al, line_buffer ; al = command letter
call comp_ul ; ..make sure its uppercase
mov bx, offset comp_cmds ; bx -> commands list
comp_par1: cmp [bx], al ; q. find command?
je comp_par2 ; a. yes .. exit loop
add bx, 4 ; bx -> next cmd entry
cmp byte ptr [bx], 0 ; q. at end of table?
jne comp_par1 ; a. no .. continue
mov dx, offset badcmd ; dx -> error message
jmp comp_die ; print line and die
comp_par2: mov si, compile_ptr ; si -> next offset
mov al, 1[bx] ; al = compiled rtn nbr
mov [si], al ; save in compiled buffer
inc si ; si -> next place in buffer
call word ptr 2[bx] ; call specific cmds parse rtn
; ..with si -> compile buffer
mov compile_ptr, si ; save next compile ptr
ret ; then return to caller
comp_pars endp
; ----------------------------------------------------------------------
; comp_init - parse initialize port command
; ----------------------------------------------------------------------
comp_init proc
xor ax, ax ; ax = zero for init'g
mov [si], ax ; init defaults
mov 2[si], ax
mov 4[si], al
mov bx, si ; bx -> output area
comp_ini2: call token ; di -> a token
jc comp_ini9 ; ..if none, exit
mov si, di ; si -> the token
call upcase ; uppercase the token
mov si, offset comp_parms ; bx -> line info table
mov cx, comp_parmn ; cx = table length
comp_ini3: call string_comp ; q. find correct type?
jc comp_ini4 ; a. yes .. exit loop
add si, comp_parml ; si -> next entry
loop comp_ini3 ; ..and try next entry
mov dx, offset badtype ; dx -> bad type msg
jmp comp_die ; ..and die gracefully
comp_ini4: mov al, 7[si] ; al = offset into output
xor ah, ah ; ax = offset
push bx ; save register
add bx, ax ; bx -> target in output
mov al, 8[si] ; al = data value
mov [bx], al ; save in compile buffer
pop bx ; restore register
call string_len ; cx = string length
add di, cx ; di -> null
mov byte ptr [di], ' ' ; fixup statement
jmp comp_ini2 ; ..loop back for next token
comp_ini9: mov si, bx ; si -> back to compile buffer
add si, 5 ; si -> next compile output area
ret ; ..and return to caller
comp_init endp
; ----------------------------------------------------------------------
; comp_send - parse send string, notify operator, and wait commands
; ----------------------------------------------------------------------
comp_send proc
call next ; q. di -> start of string?
jnc comp_send1 ; a. yes .. continue
mov dx, offset missingmsg ; dx -> error msg
jmp comp_die ; give message and quit
comp_send1: call comp_copy ; copy rest of line
ret ; ..then return to caller
comp_send endp
; ----------------------------------------------------------------------
; comp_time - parse timeout command
; ----------------------------------------------------------------------
comp_time proc
call token ; get timeout value
push si ; save register
mov si, di ; si -> token
call atoi ; ax = nbr
pop si ; restore register
or ax, ax ; q. any time?
jz comp_time1 ; a. no .. save zero ticks
cwd ; dx:ax = nbr of seconds
mov cx, 182 ; cx = 18.2 ticks/second
mul cx ; dx:ax = ticks * 10
mov cx, 10 ; cx = divisor
div cx ; ax = nbr of ticks
comp_time1: mov [si], ax ; save value
add si, 2 ; si -> next compile output area
mov word ptr [si], -1 ; init label field to -1
call token ; get label string
jc comp_time9 ; ..exit if no label given
call comp_ltoo ; ax = label offset
mov [si], ax ; save in compile buffer
comp_time9: add si, 2 ; si -> next compile output area
ret ; return to caller
comp_time endp
; ----------------------------------------------------------------------
; comp_hang - parse hangup command
; ----------------------------------------------------------------------
comp_hang proc
ret ; return to caller
comp_hang endp
; ----------------------------------------------------------------------
; comp_down - parse download command
; ----------------------------------------------------------------------
comp_down proc
call next ; get protocol/operands
call comp_copy ; copy to compile buffer
ret ; return to caller
comp_down endp
; ----------------------------------------------------------------------
; comp_what - parse prompt command
; ----------------------------------------------------------------------
comp_what proc
call token ; get timeout value
mov al, [di] ; al = prompt variable
call comp_ul ; ..and turn into uppercase
call string_len ; cx = string length
add di, cx ; di -> null
mov byte ptr [di], ' ' ; fixup statement
cmp al, 'A' ; q. valid variable (A-Z)?
jl comp_wha1 ; a. no .. give error msg
cmp al, 'Z' ; q. within upper limit?
jle comp_wha2 ; a. yes .. good, continue
comp_wha1: mov dx, offset badvariable ; dx -> error message
jmp comp_die ; ..then give msg and die
comp_wha2: sub al, 'A' - 9 ; al = var nbr in replacable tbl
push ax ; save prompt entry nbr
call next ; q. find prompt in command
jnc comp_wha3 ; a. yes .. continue
cmp byte ptr [si-1], 16 ; q. equate statement
je comp_wha3 ; a. yes .. allow null string
mov dx, offset missingmsg ; dx -> error msg
jmp comp_die ; give message and quit
comp_wha3: call comp_copy ; copy rest of line
pop ax ; restore register
mov [si], al ; save prompt character
inc si ; si -> next compile location
ret ; ..then return to caller
comp_what endp
; ----------------------------------------------------------------------
; comp_goto - parse goto label command
; ----------------------------------------------------------------------
comp_goto proc
call token ; q. get label?
jnc comp_goto1 ; a. yes .. continue
mov dx, offset nolabel ; dx -> error message
jmp comp_die ; give msg and quit
comp_goto1: mov byte ptr 8[di], 0 ; trim length if too long
call comp_ltoo ; ax = label offset
mov [si], ax ; save in compile buffer
add si, 2 ; si -> next compile output area
ret ; return to caller
comp_goto endp
; ----------------------------------------------------------------------
; comp_label - parse label statement
; ----------------------------------------------------------------------
comp_label proc
dec si ; si -> correct output area
push si ; save registers
call token ; get the label token
jnc comp_labe1 ; a. yes .. continue
mov dx, offset lab_missing ; dx -> error message
jmp comp_die ; give msg and quit
comp_labe1: mov ax, si ; ax -> current compile buffer
sub ax, offset compile_buf ; ax = offset into compile buffer
xor bx, bx ; clear addr of an open slot
mov cx, sym_number ; cx = loop count
mov si, di ; si -> new label
mov di, offset symbols ; di -> symbol table
comp_labe2: cmp sym_flag[di], 0 ; q. unused entry?
jne comp_labe3 ; a. no .. continue
or bx, bx ; q. need an open entry?
jnz comp_labe5 ; a. no .. continue
mov bx, di ; bx -> unused entry
jmp short comp_labe5 ; ..continue with common code
comp_labe3: call string_comp ; q. find a previous reference?
jnc comp_labe5 ; a. no .. try next
cmp sym_flag[di], 1 ; q. referenced entry?
je comp_labe4 ; a. yes .. continue
mov dx, offset duplabel ; dx -> error message
jmp comp_die ; give message and quit
comp_labe4: mov sym_flag[di], 0 ; make entry usable again
push di ; save register
mov di, sym_offset[di] ; di -> compile buffer reference
mov [di], ax ; save reference
pop di ; restore register
jmp short comp_labe2 ; ..check if we need a free entry
comp_labe5: add di, sym_entry ; di -> next entry
loop comp_labe2 ; ..and loop to next entry
or bx, bx ; q. any free entries?
jnz comp_labe6 ; a. yes .. continue
mov dx, offset tablefull ; dx -> error message
xor ax, ax ; ah = no help
call die ; give err msg and die
comp_labe6: mov di, bx ; di -> new unresolved entry
call string_copy ; copy name to table
mov sym_flag[bx], 2 ; show entry in use
pop si ; restore register
mov sym_offset[bx], si ; save reference for fixup
ret ; ..and return to caller
comp_label endp
; ----------------------------------------------------------------------
; comp_nada - parse comment line
; ----------------------------------------------------------------------
comp_nada proc
dec si ; don't compile in an opcode
ret ; just return to caller
comp_nada endp
; ----------------------------------------------------------------------
; comp_wait - parse wait command
; ----------------------------------------------------------------------
comp_wait proc
call token ; get wait value
push si ; save register
mov si, di ; si -> token
call atoi ; ax = nbr
pop si ; restore register
or ax, ax ; q. any time to wait?
jz comp_wait1 ; a. no .. save zero ticks
cwd ; dx:ax = nbr of seconds
mov cx, 182 ; cx = 18.2 ticks/second
mul cx ; dx:ax = ticks * 10
mov cx, 10 ; cx = divisor
div cx ; ax = nbr of ticks
comp_wait1: mov [si], ax ; save value
add si, 2 ; si -> next compile output area
ret ; return to caller
comp_wait endp
; ----------------------------------------------------------------------
; comp_opt - parse display options command
; ----------------------------------------------------------------------
comp_opt proc
call token ; di -> next token
push si ; save register
mov si, di ; si -> token
call atoi ; ax = baud rate
pop si ; restore register
mov [si], ax ; save token in compile buffer
add si, 2 ; si -> next compile output area
ret ; ..and return to caller
comp_opt endp
; ----------------------------------------------------------------------
; comp_check - check for undefines
; ----------------------------------------------------------------------
comp_check proc
xor bx, bx ; clear error found flag
mov cx, sym_number ; cx = loop count
mov di, offset symbols ; di -> symbol table
comp_chec1: cmp sym_flag[di], 1 ; q. referenced and not resolved?
jne comp_chec3 ; a. no .. give error
or bx, bx ; q. 1st time?
jnz comp_chec2 ; a. no .. continue
inc bx ; bx = error found
mov dx, offset undefined ; dx -> header error msg
mov ah, 9h ; ah = print string
int 21h ; display error line
comp_chec2: push di ; save register
mov si, di ; si -> symbol entry
add si, sym_name ; si -> symbol name
mov di, offset undef_item ; di -> part of error msg
call string_copy ; copy in symbol name
mov si, offset crlf$ ; si -> message terminator
call string_copy ; copy msg ending
mov dx, offset undef_msg ; dx -> error message
mov ah, 9h ; ah = print string
int 21h ; display error line
pop di ; restore register
comp_chec3: add di, sym_entry ; di -> next entry
loop comp_chec1 ; ..and check next entry
or bx, bx ; q. any errors?
jz comp_chec9 ; a. no .. continue
mov dx, offset crlf$ ; dx -> just a <CR><LF>
xor ax, ax ; ax = no help
call die ; ..and exit gracefully
comp_chec9: ret ; ..now return to caller
comp_check endp
; ----------------------------------------------------------------------
; comp_ltoo - label to offset
;
; entry: di -> label string
; si = current compile buffer offset
; exit: ax = label offset or -1
; ----------------------------------------------------------------------
comp_ltoo proc
push si ; save register
mov ax, si ; ax = current compile buff offset
xor bx, bx ; clear addr of an open slot
mov cx, sym_number ; cx = loop count
mov si, di ; si -> new label
mov di, offset symbols ; di -> symbol table
comp_lto1: cmp sym_flag[di], 2 ; q. resolved entry?
jne comp_lto2 ; a. yes .. continue
call string_comp ; q. find entry?
jnc comp_lto3 ; a. no .. try next
mov ax, sym_offset[di] ; ax -> compile buffer
sub ax, offset compile_buf ; ax = offset of label
jmp short comp_lto9 ; ..exit via common point
comp_lto2: or bx, bx ; q. need an open entry?
jnz comp_lto3 ; a. no .. continue
cmp sym_flag[di], 0 ; q. unused entry?
jnz comp_lto3 ; a. no .. continue
mov bx, di ; bx -> unused entry
jmp short comp_lto3 ; ..continue with common code
comp_lto3: add di, sym_entry ; di -> next entry
loop comp_lto1 ; ..and loop to next entry
or bx, bx ; q. any free entries?
jnz comp_lto4 ; a. yes .. continue
mov dx, offset tablefull ; dx -> error message
xor ax, ax ; ah = no help
call die ; give err msg and die
comp_lto4: mov di, bx ; di -> new unresolved entry
mov sym_flag[di], 1 ; show entry in use
mov sym_offset[di], ax ; save reference for fixup
call string_copy ; copy name to table
mov ax, -1 ; ax = dummy value
comp_lto9: pop si ; restore register
ret ; ..and return to caller
comp_ltoo endp
; ----------------------------------------------------------------------
; comp_write - write compile buffer
;
; entry: compile buffer
; exit: ax = compiled filesize
; ----------------------------------------------------------------------
comp_write proc
mov ah, 3eh ; ah = close file handle
mov bx, scr_handle ; bx = input file handle
int 21h ; call DOS
mov di, offset scriptfile ; di -> script filename
mov al, '.' ; al = search character
call string_len ; cx = string length
repne scasb ; find the period, if any
mov si, offset bdc ; si -> compiled script extension
call string_copy ; copy our extension
mov dx, offset scriptfile ; dx -> filename
mov ah, 3ch ; ax = create file
xor cx, cx ; cx = normal file
int 21h ; call DOS
jnc comp_writ1 ; ..if ok, continue
mov dx, offset wontopen ; dx -> error message
xor ax, ax ; ax = give msg only
call die ; ..give 'em some help
comp_writ1: mov bx, ax ; bx = file handle
mov ah, 40h ; ah = write file
lea dx, script_id ; dx -> script id bytes
mov cx, 3 ; cx = length of special hdr
int 21h ; call DOS
mov si, compile_ptr ; si -> next compile buffer addr
mov dx, offset compile_buf ; dx -> output buffer
mov byte ptr [si], 0 ; make last entry be a null
inc si ; si -> past last entry
sub si, dx ; si = length used
mov cx, si ; cx = length to write
push cx ; save .bdc filesize
mov ah, 40h ; ah = write
int 21h ; call DOS
or ax, ax ; q. ok?
jnz comp_writ2 ; a. yes .. continue
mov dx, offset cantwrite ; dx -> error message
xor ax, ax ; ax = give msg only
call die ; ..give 'em some help
comp_writ2: mov ah, 3eh ; ah = close file handle
int 21h ; call DOS
pop ax ; ax = compiled script size
inc ax ; ..
inc ax ; ax = filesize
ret ; ..then return to caller
comp_write endp
; ----------------------------------------------------------------------
; comp_stats - print completion msg
;
; entry: ax = output file size
; ----------------------------------------------------------------------
comp_stats proc
push ax ; save register
mov ah, 9h ; ah = print string
mov dx, offset compdone ; dx -> completion message
int 21h ; display part 1 of message
pop ax ; restore register
mov bx, 10 ; setup for itoa()
xor dx, dx ; dx = zero for the divides
mov di, offset compamt + 5 ; di -> lsb of size
comp_stat1: div bx ; dx = digit for this place
add dx, '0' ; dl = ascii digit
mov [di], dl ; store in output area
xor dl, dl ; dl = 0 for rest of divides
dec di ; di -> next location
or ax, ax ; q. any more signif digits?
jnz comp_stat1 ; a. yes .. continue
mov dx, di ; dx -> part 2 of message
xor ax, ax ; ax = no help
call die ; ..and quit, gracefully
comp_stats endp
; ----------------------------------------------------------------------
; comp_die - compiler's die routine
;
; entry: dx -> specific error message
; ----------------------------------------------------------------------
comp_die proc
mov ah, 9h ; ah = print string
int 21h ; display error message
mov di, offset line_buffer ; di -> input line
call string_len ; cx = string length
add di, cx ; di -> null character
mov si, offset crlf$ ; si -> line terminator
mov cx, 4 ; cx = length of terminator
call string_copy ; copy our extension
mov dx, offset line_buffer ; dx -> input line
xor ax, ax ; ax = no help needed
jmp die ; ..then die
comp_die endp
; ----------------------------------------------------------------------
; string_comp - compare strings
;
; entry: si -> string 1
; di -> string 2
; exit: carry = equal
; ----------------------------------------------------------------------
string_comp proc
push ax ; save registers
push cx
push di
push si
call string_len ; cx = length
inc cx ; cx = now includes null character
repe cmpsb ; q. strings equal?
jz string_cp1 ; a. yes .. set carry
clc ; else .. clear carry flag
jmp short string_cp9 ; ..and exit via common code
string_cp1: stc ; show strings equal
string_cp9: pop si ; restore registers
pop di
pop cx
pop ax
ret ; ..and return to caller
string_comp endp
; ----------------------------------------------------------------------
; Compile buffer .. nothing past this
; ----------------------------------------------------------------------
compile_buf db ? ; compiled buffer
mainline ends
end begin