;***************************************************** ;* ;* 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. ;* 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 jmps tmp db 'COPYRIGHT (c) 1983, DIGITAL RESEARCH 3/28/83. ' ;=== 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