
;*****************************************************
;*
;*	Terminal Message Processor
;*
;*	The TMP determines the user interface to MPM.
;*	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 MP/M-86
;*	SYSTEM'S GUIDE.
;*
;*****************************************************


true		equ	0ffh
false		equ	0
unknown		equ	0
mpmint		equ	224		; int vec for mpm

mpm86		equ	false		; CCP/M if false

cr		equ	13
lf		equ	10

mpm_conout	equ	2
mpm_conwrite	equ	9
mpm_conread	equ	10
mpm_diskselect	equ	14
mpm_openfile	equ	15
mpm_closefile	equ	16
mpm_readfile	equ	20
mpm_getdefdisk	equ	25
mpm_setdma	equ	26
mpm_usercode	equ	32
mpm_freedrive	equ	39
mpm_conattach	equ	146
mpm_condetach	equ	147
mpm_setdefcon	equ	148
mpm_clicmd	equ	150
mpm_parse	equ	152
mpm_setdeflst	equ	160
mpm_getdeflst	equ	164

ps_run		equ	00	; on ready list root
pf_sys		equ	001h	; system process
pf_keep		equ	002h	; do not terminate

s_mpmseg   equ	word ptr 40H	;begin MPM 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

rsp_top	     equ  0
rsp_md	     equ  008h
rsp_pd	     equ  010h
rsp_uda	     equ  040h
rsp_bottom   equ  140h

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

;===
mpm:	; INTERFACE ROUTINE FOR SYSTEM ENTRY POINTS
;===

	int mpmint ! ret

;===
tmp:	; PROGRAM MAIN - INITIALIZATION
;===

		; set default console # = TMP#
	mov dl,defconsole ! call setconsole

		; set default disk = system drive if MP/M, A: if CCP/M
if mpm86
	push ds ! mov ds,sysdatseg
	mov dl,.s_sysdisk ! pop ds
endif
if not mpm86
	xor dl,dl
endif
	call setdisk

if mpm86
	mov dl,defconsole		;set default user # = console
endif
if not mpm86
	xor dl,dl			;all TMPs come up user 0
endif					;in CCP/M
	call setuser

	call attach			;print version
	push ds ! mov ds,sysdatseg
	mov dx,.s_version
	mov ds,.s_mpmseg
	call print_ds_string ! pop ds
	call detach

	mov al,defconsole		;look for startup file
	add tmpnum,al			;works for 1st 10 TMPS
	mov dx,offset fcb
	mov cl,mpm_openfile
	call mpm
	cmp al,0ffh
	je nostartup
	    mov dx,offset clicb_cmd
	    mov cl,mpm_setdma
	    call mpm
	    mov dx,offset fcb
	    mov cl,mpm_readfile
	    call mpm
	    push ax
	    mov dx,offset fcb
	    mov cl,mpm_closefile
	    call mpm
	    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
		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 freedrive

		; 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
	    mov dl,bl ! call prnum
	    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 conread

startup:
		; echo newline
	    mov dl,lf ! call prchar

		; make sure not a null command
	    lea bx,clicb_cmd
	    cmp read_blen,0 ! je gonextcmd
		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 gonextcmd
			cmp dl,15 ! ja gonextcmd

				; select default disk
			    call setdisk
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,mpm_clicmd
		    call mpm
		    cmp bx,0 ! jne clierror
		        jmp nextcommand

;========
clierror:
;========
; Cli call unsuccesful, analyze and display err msg
;	input: CX = ERROR CODE

		;null command?
	cmp cx,e_nullcmd ! jne not_nullcmd
	    mov cmdsent,false
	    jmp nextcommand
not_nullcmd:
		;no memory?
	cmp cx,e_no_memory ! jne memory_ok
	    mov dx,offset memerr ! jmp showerr
memory_ok:
		;no pd in table?
	cmp cx,e_no_pd ! jne pd_ok
	    mov dx,offset pderr ! jmp showerr
pd_ok:
		;bad file spec?
	cmp cx,e_badfname   ! je fname_bad
	cmp cx,e_illdisk    ! je fname_bad
	cmp cx,e_ill_passwd ! je fname_bad
	cmp cx,e_badftype   ! jne fname_ok
fname_bad:  mov dx,offset fnameerr ! jmp showerr
fname_ok:
		;bad load?
	cmp cx,e_bad_load ! je load_bad
	cmp cx,e_bad_read ! jne load_ok
load_bad:   mov dx,offset loaderr ! jmp showerr
load_ok:
		;bad open?
	cmp cx,e_bad_open ! jne open_ok
	    mov dx,offset openerr ! jmp showerr
open_ok:
		;RSP que full?
	cmp cx,e_q_full ! jne que_ok
	    mov dx,offset qfullerr ! jmp showerr
que_ok:
		;Aborted?
	cmp cx,e_abort ! jne no_abort
	    mov dx,offset aborterr ! jmp showerr
no_abort:
		;Bad read?
	cmp cx,e_bad_read ! jne read_ok
	    mov dx,offset readerr ! jmp showerr
read_ok:
		;some other error...
	mov dx,offset catcherr
	;jmp showerr

showerr:	; Print Error String
		; input: DX = address of Error
		;             string in CSEG

	push dx
	mov dx,offset savebuf ! call print_ds_string
	mov dl,':' ! call prchar
	mov dl,' ' ! call prchar
	pop dx
	call printstring ! call crlf
	jmp nextcommand	

parsefilename:	; SI = fcb   DI = string
		mov cx,mpm_parse
		mov bx,offset pcb
		mov [bx],di ! mov 2[bx],si
		mov dx,bx ! jmp mpm
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,mpm_conout ! jmp mpm1
getuser:	mov dl,0ffh
setuser:	mov cl,mpm_usercode ! jmp mpm1
crlf:		mov dx,offset crlfstr
		;jmp printstring
printstring:	push ds ! mov ax,cs ! mov ds,ax
		call print_ds_string ! pop ds ! ret
print_ds_string:mov cl,mpm_conwrite ! jmps mpm1
setconsole:	mov cl,mpm_setdefcon ! jmps mpm1
setdisk:	mov cl,mpm_diskselect ! jmps mpm1
getdisk:	mov cl,mpm_getdefdisk ! jmps mpm1
setlist:	mov cl,mpm_setdeflst ! jmps mpm1
getlist:	mov cl,mpm_getdeflst ! jmps mpm1
attach:		mov cl,mpm_conattach ! jmps mpm1
detach:		mov cl,mpm_condetach ! jmps mpm1
conread:	mov cl,mpm_conread ! jmps mpm1
freedrive:	mov cl,mpm_freedrive ! jmps mpm1
mpm1:		jmp mpm

;*****************************************************
;*
;*	CONSTANTS (IN SHARED CODE SEGMENT)
;*
;*****************************************************

prompt		db	'>$'
crlfstr		db	13,10,'$'
memerr		db	'?Not Enough Memory$'
pderr		db	'?PD Table Full$'
fnameerr	db	'?Bad File Spec$'
loaderr		db	'?Load Error$'
openerr		db	'?Can''t Find Command$'
catcherr	db	'?$'
qfullerr	db	'?RSP Command Que Full$'
aborterr	db	'?CLI Abort$'
readerr		db	'?Read Error$'

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
		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,offset dma,0,0	;0-7
		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
		dw	0,0,0,0			;60-67


	org	rsp_bottom

dma		rb	128

stack		dw	0cccch,0cccch,0cccch
		dw	0cccch,0cccch,0cccch
		dw	0cccch,0cccch,0cccch
		dw	0cccch,0cccch,0cccch
stack_top	dw	offset tmp	; code offset
		dw	unknown		; code seg
		dw	unknown		; init. flags

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, '$'
tmpnum		db	'0'
		db	'$     SUP'
		rb	20
		db	0	;current record

savebuf		rb	128

		db	0	;make sure hex is formed
	end
