Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

631 lines
14 KiB
Plaintext

;*****************************************************
;*
;* Terminal Message Processor
;*
;* The TMP determines the user interface to CCP/M.
;* Much of the interface is available though
;* system calls. This TMP takes advantage of
;* as much as possible for simplicity. The TMP
;* could, for instance, be easily modified to
;* force logins and have non-standard defaults.
;*
;* With a little more work, The TMP could do all
;* command parsing and File Loading instead of
;* using the CLI COMMAND FUNCTION. This is also
;* the place to AUTOLOAD programs for specific
;* users. Suggestions are given in the CCP/M-86
;* SYSTEM'S GUIDE.
;*
;*****************************************************
title 'Terminal Message Processor - CCP/M-86 2.0'
; Some common equates
true equ 0ffh
false equ 0
cr equ 13 ; carraige return
lf equ 10 ; linefeed
tab equ 9 ; tab char
; CCP/M-86 system functions used by the TMP
osint equ 224 ; interrupt number for CCP/M
; system calls
c_write equ 2 ; console functions
c_writebuf equ 9
c_readbuf equ 10
c_attachc equ 146
c_detachc equ 147
c_setnum equ 148
l_setnum equ 160 ; list device functions
l_getnum equ 164
f_open equ 15 ; file functions
f_close equ 16
f_read equ 20
f_setdma equ 26
f_parse equ 152
drv_set equ 14 ; drive functions
drv_get equ 25
drv_free equ 39
dir_usernum equ 32 ; directory functions
p_cli equ 150 ; process control functions
; Process descriptor flags
ps_run equ 00 ; on ready list root
pf_sys equ 001h ; system process
pf_keep equ 002h ; do not terminate
; Some locations in the system data segment
s_ccpmseg equ word ptr 40H ;begin CCPM segment
s_sysdisk equ byte ptr 04bh ;system disk
s_ncns equ byte ptr 47H ;sys. consoles
s_version equ word ptr 78h ;ofst ver. str in SUP
; Some RSP format equates
rsp_top equ 0
rsp_md equ 008h
rsp_pd equ 010h
rsp_uda equ 040h
rsp_bottom equ 140h
; Error codes returned by the CLI
e_no_memory equ 3 ; cant find memory
e_no_pd equ 12 ; no free pd's
e_q_full equ 15 ; full queue
e_illdisk equ 23 ; illegal disk #
e_badfname equ 24 ; illegal filename
e_badftype equ 25 ; illegal filetype
e_bad_load equ 28 ; bad ret. from BDOS load
e_bad_read equ 29 ; bad ret. from BDOS read
e_bad_open equ 30 ; bad ret. from BDOS open
e_nullcmd equ 31 ; null command sent
e_ill_lst equ 37 ; illegal list device
e_ill_passwd equ 38 ; illegal password
e_abort equ 40 ; aborted in CLI
;*****************************************************
;*
;* TMP Shared Code and Constant Area
;*
;*****************************************************
cseg
org 0
;===
tmp: ; PROGRAM MAIN - INITIALIZATION
;===
; Set default console # = TMP#
mov dl,defconsole ! call setconsolenum
; Set default disk = system drive
push ds ! mov ds,sysdatseg
mov dl,.s_sysdisk ! pop ds ;get system drive from
call setdisk ;system data segment
xor dl,dl ;all TMPs come up user 0
call setuser
call attach ;print version
push ds ! mov ds,sysdatseg
mov dx,.s_version
mov ds,.s_ccpmseg
call print_ds_string ! pop ds
call detach
push ds ! pop es
mov si,offset pd_ascii_num
mov di,offset startupnum
mov cx,3
rep movsb
mov dx,offset fcb
mov cl,f_open ;try to open the startup file
call ccpm ;on default drive which is
cmp al,0ffh ;the system drive
je nostartup
mov dx,offset clicb_cmd ;use the CLI buffer for this
mov cl,f_setdma ;one time one sector read
call ccpm
mov dx,offset fcb
mov cl,f_read
call ccpm
push ax
mov dx,offset fcb
mov cl,f_close
call ccpm
pop ax
test al,al
jnz nostartup
mov ax,ds
mov es,ax
mov al,cr
mov cx,128
mov di,offset clicb_cmd
repne scasb
jne nostartup ;didn't find a carriage return
inc di ;include cr lf in line
mov byte ptr [di],'$'
sub di,offset clicb_cmd
mov ax,di
sub ax, 2
mov read_blen, al
mov dx,offset supmsg
call printstring
mov dx,offset clicb_cmd
call print_ds_string
jmps startup
nostartup:
; THIS IS WHERE A LOGIN ROUTINE MIGHT
; BE IMPLEMENTED. THE DATA FILE THAT
; CONTAINS THE USER NAME AND PASSWORD
; MIGHT ALSO CONTAIN AN INITIAL DEFAULT
; DISK AND USER NUMBER FOR THAT USER.
;===========
nextcommand: ; LOOP FOREVER
;===========
; free drive
mov dx,0ffffh ! call drive_free
; attach console
call attach
; print CR,LF if we just sent command
cmp cmdsent,false ! je noclearline
mov cmdsent,false
call crlf
noclearline:
; set up and print user prompt
; get current default user # and disk
; this call should be made on every
; loop in case the last command
; has changed the default.
mov dl,cr ! call prchar
call getuser
test bl,bl ! jz nozero ;don't print user 0 prompt
mov dl,bl ! call prnum
nozero:
call getdisk
mov dl,'A' ! add dl,bl
call prchar
mov dx,offset prompt
call print_string
; Read Command from Console
mov dx,offset read_buf ! call conreadbuf
startup:
; echo newline
mov dl,lf ! call prchar
; make sure not a null command
lea bx,clicb_cmd
cmp read_blen,0 ! je gonextcmd
deblank:
cmp byte ptr [bx],' ' ! je zapblank
cmp byte ptr [bx],tab ! jne noblanks
zapblank:
inc bx ! dec read_blen ! jmps deblank
noblanks:
lea ax,clicb_cmd ! cmp ax,bx ! je chksemi
; remove leading blanks
push ds ! pop es ! xor ch,ch ! mov cl,read_blen
mov di,ax ! mov si,bx ! cld ! rep movsb
mov bx,ax
chksemi: ; see if line starts with semicolon
cmp byte ptr [bx],';' ! je gonextcmd
; see if disk change
; if 'X:' change def disk to X
cmp read_blen,2 ! jne clicall
cmp byte ptr 1[bx],':'
jne clicall
; change default disk
mov dl,[bx] ;get disk name
and dl,5fh ;Upper Case
sub dl,'A' ;disk number
; check bounds
cmp dl,0 ! jb baddrive
cmp dl,15 ! ja baddrive
; select default disk
call setdisk ! jmp gonextcmd
baddrive: mov dx,offset errstr ! call printstring
mov dx,offset drverr ! call printstring ! call crlf
gonextcmd: jmp nextcommand
;=======
clicall: ; SEND CLI COMMAND
;=======
; put null at end of input
mov bx,offset clicb_cmd
mov al,read_blen ! mov ah,0
add bx,ax ! mov byte ptr [bx],0
; copy command string for error
; reporting later and to check
; for built in commands...
mov cx,64
mov si,offset clicb_cmd
mov di,offset savebuf
push ds ! pop es
rep movsw
; parse front to see if
; built in command
mov si,offset fcb
mov di,offset savebuf
call parsefilename
jcxz goodparse
sub bx,bx ! mov bl,read_blen
add bx,offset savebuf
mov byte ptr [bx],'$'
jmp clierror
goodparse: mov parseret,bx
cmp bx,0 ! jne haveatail
mov bl,read_blen
add bx,offset savebuf
haveatail: mov byte ptr [bx],'$' ! inc bx
cmp fcb,0 ! je try_builtin
jmp not_builtin
; is it USER command?
try_builtin: mov si,offset fcb ! inc si
mov di,offset usercmd
push cs ! pop es
mov cx,4 ! repz cmpsw
jnz notuser
mov si,offset fcb
mov di,parseret
cmp di,0 ! je pruser
inc di
call parsefilename
cmp cx,0 ! jne pruser
mov si,offset fcb
inc si
mov dx,[si]
call a_to_b
cmp bl,15 ! ja usererr
mov dl,bl
call setuser
jmp pruser
usererr: mov dx,offset usererrmsg
call printstring
pruser: mov dx,offset usermsg
call printstring
call getuser
mov dl,bl ! call prnum
call crlf
jmp nextcommand
notuser:
mov si,offset fcb ! inc si
mov di,offset printercmd
push cs ! pop es
mov cx,4 ! repz cmpsw
jnz notprinter
mov si,offset fcb
mov di,parseret
cmp di,0 ! je prprinter
inc di
call parsefilename
cmp cx,0 ! jne prprinter
mov si,offset fcb
inc si
mov dx,[si]
call a_to_b
cmp bl,0ffh
je printererr
mov dl,bl
call setlist
jcxz prprinter
printererr: mov dx,offset printemsg
call printstring
prprinter: mov dx,offset printermsg
call printstring
call getlist
mov dl,bl ! call prnum
call crlf
jmp nextcommand
notprinter:
not_builtin:
; initialize Cli Control Block
mov clicb_net,0
; make cli call
mov cmdsent,true
lea dx,clicb ! mov cl,p_cli
call ccpm
cmp bx,0 ! jne clierror
jmp nextcommand
;========
clierror:
;========
; Cli call unsuccesful, analyze and display err msg
; input: CX = ERROR CODE
mov si,(offset clierrtab)-4
nexterr:
add si,4
cmp cs:word ptr [si],0ffffh ! je unknownerr
cmp cx,cs:[si] ! jne nexterr
unknownerr:
mov dx,cs:2[si]
; jmps showerr
showerr: ; Print Error String
;------- ; input: DX = address of Error
; string in CSEG
; if DX=0 then NULL COMMAND
cmp dx,0 ! jne perr
mov cmdsent,false ! jmp nextcommand
perr: push dx ! call crlf
mov dx,offset errstr ! call printstring
pop dx ! call printstring ! call crlf
mov dx,offset cmdstr ! call printstring
mov dx,offset savebuf ! call print_ds_string ! call crlf
jmp nextcommand
parsefilename: ; SI = fcb DI = string
mov cx,f_parse
mov bx,offset pcb
mov [bx],di ! mov 2[bx],si
mov dx,bx ! jmp ccpm
a_to_b: ;dl = 1st char, dh = 2nd char
cmp dh,' ' ! jne atob2char
mov dh,dl ! mov dl,'0'
atob2char: cmp dh,'0' ! jb atoberr
cmp dh,'9' ! ja atoberr
cmp dl,'0' ! jb atoberr
cmp dl,'9' ! ja atoberr
sub dh,'0' ! sub dl,'0'
mov ax,0 ! mov al,dl
push dx ! mov cl,10
mul cl ! pop dx
mov dl,dh ! mov dh,0
add ax,dx
mov bx,ax ! ret
atoberr: mov bl,0ffh ! ret
prnum: ; dl = num (0-15)
cmp dl,10 ! jb prnum_one
push dx
mov dl,'1' ! call prchar
pop dx ! sub dl,10
prnum_one: add dl,'0'
; jmp prchar
prchar: mov cl,c_write ! jmp ccpm
getuser: mov dl,0ffh
setuser: mov cl,dir_usernum ! jmp ccpm
crlf: mov dx,offset crlfstr
;jmps printstring
printstring: push ds ! mov ax,cs ! mov ds,ax
call print_ds_string ! pop ds ! ret
print_ds_string:mov cl,c_writebuf ! jmps ccpm
setconsolenum: mov cl,c_setnum ! jmps ccpm
setdisk: mov cl,drv_set ! jmps ccpm
getdisk: mov cl,drv_get ! jmps ccpm
setlist: mov cl,l_setnum ! jmps ccpm
getlist: mov cl,l_getnum ! jmps ccpm
attach: mov cl,c_attachc ! jmps ccpm
detach: mov cl,c_detachc ! jmps ccpm
con_readbuf: mov cl,c_readbuf ! jmps ccpm
drivefree: mov cl,drv_free !; jmps ccpm
;====
ccpm: ; INTERFACE ROUTINE FOR SYSTEM ENTRY POINTS
;====
int osint ! ret
;*****************************************************
;*
;* CONSTANTS (IN SHARED CODE SEGMENT)
;*
;*****************************************************
clierrtab dw e_nullcmd, 0 ;null command
dw e_no_memory, memerr ;No memory
dw e_no_pd, pderr ;No unused PD
dw e_badfname, fnameerr;Ill. command
dw e_illdisk, fnameerr;Ill. disk
dw e_ill_passwd, fnameerr;Ill. password
dw e_badftype, fnameerr;Ill. type
dw e_bad_load, loaderr ;
dw e_bad_read, loaderr ;
dw e_bad_open, openerr ;
dw e_q_full, qfullerr;
dw e_abort, aborterr;
; a few extra entries for future errors
dw 0ffffh, catcherr;
dw 0ffffh, catcherr;
dw 0ffffh, catcherr;
dw 0ffffh, catcherr;
prompt db '>$'
crlfstr db 13,10,'$'
errstr db 'CP/M Error: $'
memerr db 'Not Enough Memory$'
pderr db 'PD Table Full$'
fnameerr db 'Bad File Spec$'
catcherr rb 0 ;Unknown Errs give
loaderr db 'Load Error$' ; Load Error Msg
openerr db 'Can''t Find Command$'
qfullerr db 'RSP Command Que Full$'
aborterr db 'CLI Abort$'
drverr db 'Invalid Drive$'
cmdstr db 'Command = $'
usererrmsg db 13,10,'Invalid User Number,'
db ' IGNORED',13,10,'$'
usermsg db 13,10,'User Number = $'
printemsg db 13,10,'Invalid Printer Number,'
db ' IGNORED',13,10,'$'
printermsg db 13,10,'Printer Number = $'
usercmd db 'USER '
printercmd db 'PRINTER '
supmsg db 'Start up command: $'
;*****************************************************
;*
;* TMP Data Area - this area is copied once for
;* each system console. The 'defconsole'
;* field is unique for each copy
;* - Each Data Area is run by a common
;* shared code segment.
;*
;*****************************************************
DSEG
org rsp_top
sysdatseg dw 0
sdatvar dw s_ncns
defconsole db 0,0
dw 0,0,0,0,0
org rsp_pd
pd dw 0,0 ; link fields
db ps_run ; status
db 198 ; priority
dw pf_sys+pf_keep ; flags
db 'Tmp' ; Name
pd_ascii_num db ' ' ; Ascii number field set by GENSYS
dw offset uda/10h ; uda seg
db 0,0 ; disk,user
db 0,0 ; ldisk,luser
dw 0ffffh ; mem
dw 0,0 ; dvract,wait
db 0,0 ; org,net
dw 0 ; parent
db 0,0 ; cns,abort
db 0,0 ; cin,cout
db 0,0 ; lst,sf3
db 0,0 ; sf4,sf5
dw 0,0 ; reserved
dw 0,0 ; pret,scratch
org rsp_uda
uda dw 0,0,0,0 ;0-7 note: no default DMA
dw 0,0,0,0 ;8-fh
dw 0,0,0,0 ;10-17
dw 0,0,0,0 ;18-1f
dw 0,0,0,0 ;20-27
dw 0,0,0,0 ;28-2f
dw 0,0,offset stack_top,0 ;30-37
dw 0,0,0,0 ;38-3f
dw 0,0,0,0 ;40-47
dw 0,0,0,0 ;48-4f
dw 0,0,0,0 ;50-57
dw 0,0,0,0 ;58-5f
db 1 ;60 INSYS <> 0
;don't switch from
;from UDA stack
;on entry to SUP
db 0 ;61
dw 0,0 ;62-64
db 0 ;66
dw 0 ;67-68
db 0 ;69
dw 0cccch,0cccch,0cccch ;6A-6F
dw 0cccch,0cccch,0cccch,0cccch ;70
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;80
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;90
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;A0
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;B0
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;C0
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;D0
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;E0
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch ;F0
dw 0cccch
stack_top dw offset tmp ; code starting point
dw 0 ; code seg - set by GENSYS
dw 0 ; init. flags - set by GENSYS
; UDA is 100H bytes long
maxcmdlen equ 128
; the Read Console Buffer and the
; Cli Control Block share the same memory
read_buf rb 0
read_maxcmd db 128
clicb rb 0
clicb_net rb 0
read_blen rb 1
clicb_cmd rb maxcmdlen + 1
cmdsent db false
parseret dw 0
pcb dw offset savebuf
dw offset fcb
fcb db 0, 'STARTUP '
startupnum db ' '
rb 20
db 0 ;current record
savebuf rb 128
db 0 ;ensure hex is formed
end