
;*****************************************************
;*
;*	Command Line Interpreter, Program Chain
;*
;*****************************************************
;=========
chain_ent:
;=========

	xor dx,dx

;=======
cli_ent:
;=======
; Create a process based on an Ascii Command Line.
; The command Line is first parsed and an FCB is
; initialized as a result.
; An attempt is made to open a queue with the filename
; of the FCB, and with the RSP flag on.
; The command tail is written to the queue if it is found.
; If the queue cannot be opened or is not and RSP type then
; we try and load the command from disk.
; If the write queue fails we return e_q_full error code and
; do not look on the disk.
; After the queue write, an console assign call attempted to
; a process with the same name and the PF_DSKLD flag off.
; Irregardless of the success of the assign we then return.
;
; If the RSP queue cannot be opened, or is not an RSP type queue then
; we make the name type in the
; FCB to be 'CMD' and attempt to open the file.  If this fails,
; so do we.
; We then obtain a Process Descriptor from the
; PD table.  Again we fail if it does.
; On a successful open, we call the BDOS load function.
; If the load fails, so do we.  The PD is
; initialized, the default console is assigned to the
; PD, the PF_DSKLD flag turned on,
; and a create process call is made.
;
;	input:	DX -> command buffer in u_wrkseg
;		It is assumed that the calling process
;		is attached to its default console
;		and is willing to lose it since it
;		will be handed to the newly created
;		process.
;		if DX = 0, assume chain w/command in DMA
;
;	output:	BX = 0 if successful
;		   = 0ffffh if failure has occured
;		CX = error code

	mov bx,rlr ! mov ax,p_flag[bx]
	push ax				;save flags on stack
if netversion
        or ax,pf_noctls
endif
if not netversion
	or ax,pf_tempkeep + pf_noctls
endif
	mov p_flag[bx],ax
if netversion
        mov cx,f_no_abort
        call osif
endif  
	push dx				;save parameter
	call cli_sync			;rentrancy stops with sync call
	pop dx				;we can save the flags
	pop cli_pflag			;and other variables in the CLI
					;data area
		; we have CLI SYNC
		; Check for Chain

	mov cli_chain,false
	cmp dx,0 ! jne cli_cli
	    mov cli_chain,true
	    mov cli_term,false
cli_cli:
		; initialize defaults from parent PD

	mov cli_dfil,false
	cmp dayfile,0ffh ! jne nodf
	    push dx ! mov cx,f_cconattch
	    call osif ! pop dx
	    cmp cx,0 ! jne nodf
		mov cli_dfil,true
		push dx
		call prtime
		pop dx
nodf:	mov bx,rlr
	mov cli_ppd,bx
	mov cl,p_dsk[bx]
	mov cli_dsk,cl
	mov cl,p_user[bx]
	mov cli_user,cl
	mov cl,p_cns[bx]
	mov cli_cns,cl
	mov cl,u_error_mode
	mov cli_err_mode,cl
	mov cx,u_dma_ofst
	mov cli_dma_ofst,cx
	mov cx,u_dma_seg
	mov cli_dma_seg,cx
	mov clierr,0

		; copy command into local area

	cmp cli_chain,true ! jne cli_cpy
	    push es ! push ds
	    mov es,sysdat
	    mov si,cli_dma_ofst
	    mov di,offset cli_cmdtail
	    mov ds,cli_dma_seg
	    mov cx,040H
	    rep movsw
	    pop ds ! pop es
	    jmp cli_parse

cli_cpy:
	push es ! push ds
	mov ds,u_wrkseg ! pop es
		; DS=Wrkseg, ES=Sysdat, SP->UDA
		; copy clicb_net
	mov si,dx ! mov di,offset cli_net
	movsb
		; copy command
	mov si,dx ! add si,clicb_cmd
	mov di,offset cli_cmdtail
	mov cx,clicblen-clicb_cmd
	rep movsb
	push es ! pop ds ! pop es

		;parse the command
cli_parse:
	call pfn ! jcxz cli_gprs
	    mov clierr,cx
	    jmp cli_exit
cli_gprs:

	call shtal

		;fcb has parsed filename
		;if not explicit disk then
		;   if not RSP try CMD
		;else try CMD

	cmp cli_fcb,0 ! jne cli_ffload
	    mov bx,(offset cli_fcb)
	    cmp fcb_plen[bx],0 ! jne cli_ffload
		call cli_checkque ! jnz cli_ffload
				;successful RSP access
cli_qful:
		    cmp cli_chain,true ! jne cli_exit2
			mov cli_term,true
cli_exit2:	    jmp cli_exit
cli_ffload:
	cmp cx,e_q_full ! jne cli_fload
	    mov clierr,cx ! jmps cli_qful

cli_checkque:
;------------
;	output: z flag on if successful

		;copy fcb.name to qpb.name

	mov si,(offset cli_fcb)+fcb_name
	mov di,(offset cli_cuspqpb)+qpb_name
	mov cx,qnamsiz/2 ! push es ! push ds ! pop es
	push si ! rep movsw

		;copy fcb.name to acb.name

	pop si ! mov cx,qnamsiz/2
	mov di,(offset cli_acb)+acb_name
	rep movsw ! pop es

		;open queue

	mov cx,f_qopen ! mov dx,(offset cli_cuspqpb)
	call osif ! jcxz cli_goodq
retcli1:    cmp cx,0 ! ret		;CX = 0ffffh on error

		;we successfully opened the queue
		;now check RSP flag
cli_goodq:
	mov bx,offset cli_cuspqpb
	mov bx,qpb_qaddr[bx]
	test q_flags[bx],qf_rsp ! jnz cli_gq
	    mov cx,e_no_queue ! jmps retcli1

		;write command tail to queue

cli_gq:	mov cx,f_cqwrite ! mov dx,offset cli_cuspqpb
	call osif ! jcxz cli_qw
	    mov cx,e_q_full ! jmps retcli1

		;successful queue write, assign console

cli_qw:	cmp cli_dfil,true ! jne noqm
	    call prcusp
noqm:	mov bx,offset cli_acb
	mov al,cli_cns ! mov acb_cns[bx],al
	mov acb_match[bx],false
	mov acb_pd[bx],1		;match on PD with DSKLD flag off
	call conasn ! xor cx,cx ! ret

cli_fload:
;---------
; Try to Load a file for execution
; The Command Line Parsed correctly and we have an FCB
; set up.  We already know there isn't a queue and a
; process by the same name  as the command.

		; Obtain a Process Descriptor

	pushf ! cli ! mov bx,pul
	cmp bx,0 ! jne cli_gpd
	    popf ! mov clierr,e_no_pd
	    jmp cli_exit
cli_gpd:
	mov si,p_link[bx] ! mov pul,si
	popf ! mov cli_pd,bx
		; zero PD
	push es ! push ds ! pop es
	mov di,bx ! mov cx,pdlen/2
	xor ax,ax ! rep stosw
	pop es

		; Initialize the PD for Load

	mov bx,cli_pd
	mov p_flag[bx],pf_table
	mov di,bx ! add di,p_name
	mov si,offset cli_fcb ! add si,fcb_name
	push es ! mov ax,ds ! mov es,ax
	mov cx,pnamsiz/2 ! rep movsw	
	pop es
	mov si,rlr
	mov al,cli_dsk ! mov p_dsk[bx],al	;inherit parents drive/user
	mov al,cli_user ! mov p_user[bx],al	;even if we load off another
						;drive or user

						;this should be in
						;process create ?

	mov al,cli_cns ! mov p_cns[bx],al
	mov al,p_lst[si]
;if mpm
;	 sub al,ncondev
;endif
	mov p_lst[bx],al

		; 3. Open the file

	mov si,(offset cli_fcb)+fcb_pwd
	mov di,offset cli_dma
	push es ! mov es,sysdat
	mov cx,4 ! rep movsw
	pop es
	mov u_dma_ofst,offset cli_dma
	mov u_dma_seg,ds

	mov si,offset cli_fcb
	mov byte ptr fcb_type[si],'C'
	mov byte ptr fcb_type+1[si],'M'
	mov byte ptr fcb_type+2[si],'D'

		; Open the CMD file

	mov u_error_mode,0feh
	call flopn
	cmp bl,0ffh ! jne cli_gopen

		; on failure,
		; if default is not system disk
		;    and not an explicit disk then
 		;	try CMD file on System disk

	    cmp bh,0 ! jne cli_bo		;extended error 
	    mov cl,srchdisk
	    cmp cl,cli_dsk ! je cli_bo		;already on system disk
	    cmp cli_fcb,0 ! jne cli_bo		;check for explicit
						;select
			; try system disk

;		mov bx,rlr
;		mov p_dsk[bx],cl
		inc cl
		mov cli_fcb,cl			;set drive byte to
		call flopn			;system disk
		cmp bl,0ffh ! je cli_bo

			;make sure SYS attribute is on...

		    mov bx,offset cli_fcb
		    test byte ptr fcb_type+1[bx],080h ! jnz cli_gopen

			;We opened a NON-SYS file.  Do explicit open
			;on user zero if not already

			call flclse
			mov bx,rlr
			cmp p_user[bx],0 ! je cli_boe
			    mov p_user[bx],0
			    call flopn
			    cmp bl,0ffh ! je cli_bo
				mov bx,offset cli_fcb
				test byte ptr fcb_type+1[bx],080h
				jnz cli_gopen
				    call flclse
				    jmps cli_boe

			;could not find CMD file

cli_bo:		    cmp bh,0 ! jne cli_rmpd2
cli_boe:		mov clierr,e_bad_open
cli_rmpd2:	    jmp cli_rmpd
cli_gopen:

		; 8. Call the load function

	mov bx,rlr
	test p_flag[bx],pf_ctlc ! jz cli_ld1
	    mov bx,0ffffh ! mov cx,e_abort
	    jmp cli_cl
cli_ld1:
	cmp cmod,true !  jne not_cmod
	    mov bx,cli_pd
	    mov si,offset cli_fcb

		;test F1 bit
	    mov p_cmod[bx],0
	    test byte ptr fcb_name[si],080h ! jz not_f1
		or p_cmod[bx],080h

		;test F2 bit
not_f1:	    test byte ptr fcb_name+1[si],080h ! jz not_f2
		or p_cmod[bx],040h

		;test F3 bit
not_f2:

;if mpm		dave brown test
	    test byte ptr fcb_name+2[si],080h
	    jz not_f3
;endif

 		or p_cmod[bx],020h

		;test F4 bit
not_f3:	    test byte ptr fcb_name+3[si],80h ! jz not_cmod
		or p_cmod[bx],070h
not_cmod:

	cmp cli_chain,true ! jne cli_kuda
	    mov bx,cli_pd
	    mov p_uda[bx],es
	    mov ax,offset inituda
	    mov cl,4 ! shr ax,cl
	    add ax,sysdat
	    mov bx,es ! mov es,ax ! mov di,0
	    mov ds,bx ! mov si,di
	    mov cx,ulen/2
	    rep movsw
	    pushf ! cli ! pop dx
	    mov ax,es
	    mov ds,sysdat
	    mov ss,ax
	    mov bx,rlr
	    mov p_uda[bx],ax
	    push dx ! popf	    
cli_kuda:
	cmp cli_dfil,true ! jne noprfil
	    call prfilnam
	    call crlf

noprfil:mov bx,cli_pd
	mov dx,offset cli_fcb
	mov cx,f_load
	cmp cli_chain,true ! jne cli_ld
	    mov cli_term,true
            mov cx,f_cload
             call osif
              jcxz cli_cl
            mov cli_term,false
        jmp cli_cl
cli_ld:	call osif
cli_cl:	push bx ! push cx
	mov u_error_mode,0
	call flclse
	pop cx ! pop bx
	jcxz cli_gload
	    cmp cx,e_abort ! jne cli_lnab
		jmp cli_rmpd
cli_lnab:   mov clierr,cx
	    jmp cli_rmpd
cli_gload:
	mov cli_bpage,bx

		; 9a. Parse Command Tail

		;	copy cmdtail to user DMA buffer

	push es ! mov es,cli_bpage
	mov di,offset bpg_dma+1
	mov si,offset cli_cmdtail
	mov cx,127
	rep movsb ! pop es	

		;	count cmd length and convert
		;	to upper case

	push ds ! mov ds,cli_bpage
	mov cl,0 ! mov di,offset bpg_dma+1
ncmdchar:
	cmp byte ptr [di],0 ! je endtail

		; convert CMD tail to UPPER CASE

	    cmp byte ptr [di],'a' ! jb nlow
		cmp byte ptr [di],'z' ! ja nlow
		    and byte ptr [di],05fh
nlow:


	    inc di ! inc cl ! jmps ncmdchar
endtail:
	mov bpg_dma,cl ! pop ds

		;	load disk init, location 50H
		;	of base page is done in LOAD

	push es ! mov es,cli_bpage

		;	init default fcb

	mov di,offset bpg_fcb0
	xor ax,ax ! stosb			;default disk
	mov al,' '
	mov cx,11 ! rep stosb			;name,type
	xor ax,ax
	mov cx,2 ! rep stosw			;other
	push ds ! push es ! pop ds
	mov si,offset bpg_fcb0
	mov cx,8 ! rep movsw
	pop ds ! pop es	

		;	if cmdtail, parse

	cmp cli_cmdtail,0 ! je ctdone
	    call pfn
	    cmp bx,0ffffh ! je ctdone

		;	copy fcb to user fcb front

		push es ! mov es,cli_bpage
		mov di,offset bpg_fcb0
		mov si,offset cli_fcb
		mov ax,fcb_pptr[si]
			; AX->password in CLI_CMDTAIL
		sub ax,offset cli_cmdtail
		add ax,offset bpg_dma + 1
			; AX->password in Base Page
		mov es:bpg_pw1ptr,ax
		mov al,fcb_plen[si]
		mov es:bpg_pw1len,al
		mov cx,8 ! rep movsw ! pop es

		;	if more cmdtail, parse

		cmp bx,0 ! je ctdone
		    push cli_pcb ! inc bx
		    mov cli_pcb,bx
		    call pfn
		    pop cli_pcb
		    cmp bx,0ffffh ! je ctdone

		;	copy 2nd fcb front

			push es ! mov es,cli_bpage
			mov di,offset bpg_fcb1
			mov si,offset cli_fcb
			mov ax,fcb_pptr[si]
				; AX->password in CLI_CMDTAIL
			sub ax,offset cli_cmdtail
			add ax,offset bpg_dma + 1
				; AX->password in Base Page
			mov es:bpg_pw2ptr,ax
			mov al,fcb_plen[si]
			mov es:bpg_pw2len,al
			mov cx,8
			rep movsw
			pop es
ctdone:

		; 10. Create the process

	cmp cli_chain,true ! jne nprior
	    mov cx,f_setprior
	    mov dx,1 ! call osif
nprior:
	mov si,cli_pd ! or p_flag[si],pf_dskld	;from disk, to differ 
	mov dx,si ! mov cx,f_createproc		;from RSP with same name
	call osif

		; 11. Assign Console to new process

	mov bx,rlr
	and p_flag[bx],not pf_ctlc

		; Check to see if user hit CTRL D
	test p_flag[bx],pf_ctld ! jz asgn
	    and p_flag[bx],not pf_ctld
	    mov bx,cli_pd
	    or p_flag[bx],pf_ctld
	    jmp cli_exit
asgn:	mov bx,offset cli_acb
	mov al,cli_cns ! mov acb_cns[bx],al
	mov ax,cli_pd ! mov acb_pd[bx],ax
	mov acb_match[bx],true
	call conasn
	mov clierr,cx

	jmps cli_exit

		; 12. All Done

cli_rmpd:	; release PD

	mov si,cli_pd

		; Release any memory that might still be
		; associated with the PD.  This could
		; happen from a CTRL C.

	cmp p_mem[si],0 ! je rmpd1
	    push ds ! push es
	    push si
	    mov si,p_mem[si]
	    push ms_start[si]
	    mov cx,f_memfree
	    mov dx,sp
	    mov ax,ss ! mov ds,ax
	    call osif
	    pop ax ! pop si
	    pop es ! pop ds
	    jmps cli_rmpd

		; Place empty PD on PUL.

rmpd1:	pushf ! cli
	mov bx,pul
	mov p_link[si],bx ! mov pul,si
	popf

		; Normal EXIT

cli_exit:	; close file and release CLI SYNC
	mov bx,rlr
	mov cl,cli_dsk ! mov p_dsk[bx],cl
	mov cl,cli_user ! mov p_user[bx],cl
	mov cl,cli_err_mode ! mov u_error_mode,cl
	mov cx,cli_dma_ofst ! mov u_dma_ofst,cx
	mov cx,cli_dma_seg ! mov u_dma_seg,cx
	cmp cli_chain,true ! jne clirls
	    mov bx,rlr ! mov si,cli_pd		;inherit calling PD's
	    mov ax,p_parent[bx]			;parent if chaining
	    mov p_parent[si],ax
	    cmp cli_term,true ! jne clirls
		and p_flag[bx],not (pf_keep+pf_sys+pf_tempkeep+pf_ctlc)
if netversion
                mov p_tkcnt[bx],0
endif
		mov cx,f_terminate		;TERM_ACT in dispatcher
		jmp osif			;releases CLI_SYNC
clirls:
	push cli_pflag
	push cli_err
	call cli_unsync
if netversion
        mov cx,f_ok_abort
        call osif
endif        
	pop dx
if netversion
        pop ax ! and ax,pf_noctls
endif
if not netversion  
	pop ax ! and ax,pf_tempkeep+pf_noctls
endif
	mov bx,rlr ! mov cx,p_flag[bx]
if netversion
        and cx,not pf_noctls
endif
if not netversion
	and cx,not pf_tempkeep+pf_noctls
endif
	or cx,ax ! mov p_flag[bx],cx
	test p_flag[bx],pf_ctlc ! jz cli_nctl
	    mov cx,f_terminate ! xor dx,dx
	    call osif
	    and p_flag[bx],not pf_ctlc
	    mov dx,e_abort

		; setup error return if needed
cli_nctl:

	mov cx,dx
	xor bx,bx
	jcxz cli_gexit
	    mov bx,0ffffh

cli_gexit:
	ret

shtal:
;---------
; setup command tail to be parsed
;	input:	AX = output of previous parsefilename

	cmp ax,0 ! je ntail

		;shift command tail to beginning
		;of command buffer

	    push ax ! sub ax,offset cli_cmdtail
	    mov cx,128 ! sub cx,ax ! shr cx,1
	    pop si ! mov di,offset cli_cmdtail
	    push es ! push ds ! pop es
	    rep movsw ! pop es
	    ret
ntail:
	mov cli_cmdtail,0
	ret

;============================
;  Various string subroutines

crlf:	mov dl,13 ! call prchar
	mov dl,10
	;jmps prchar

prchar:	
	mov si,u_conccb
	mov di,rlr
	cmp [si],di ! jne prr
	    mov cx,f_conout ! jmp osif
prr:	ret

prtime:	mov dl,tod_hr ! call prnum
	mov dl,':' ! call prchar
	mov dl,tod_min ! call prnum
	mov dl,':' ! call prchar
	mov dl,tod_sec ! call prnum
	mov dl,' ' ! jmps prchar

prnum:	push dx ! mov cl,4
	shr dl,cl ! add dl,'0'
	call prchar
	pop dx ! and dl,0fh
	add dl,'0' ! jmps prchar

prfilnam:
	call prdisk
	mov dx,(offset cli_fcb)+fcb_name
	call prnam
	mov dl,'.' ! call prchar
	mov dx,(offset cli_fcb) + fcb_type
	call prtyp
	mov dl,' ' ! call prchar
	mov bx,offset cli_fcb
	test byte ptr fcb_name+7[bx],080h ! jnz pruser
	    cmp cli_user,0 ! je pret
		mov bx,rlr
		cmp p_user[bx],0 ! je pruser
pret:	    ret

pruser: mov dx,offset userstr
	jmps prcsm

prdisk:	mov dl,cli_fcb
	cmp dl,0 ! je prpddsk
	    dec dl ! jmps prdsk1
prpddsk:
	mov bx,rlr
	mov dl,p_dsk[bx]
prdsk1:	add dl,'A' ! call prchar
	mov dl,':' ! jmp prchar

prcusp:	mov dx,(offset cli_cuspqpb) + qpb_name
	call prnam ! mov dx,offset questr
	call prcsm ! jmp crlf

prcsm:	mov si,u_conccb
	mov di,rlr
	cmp [si],di ! jne prr1
	    xor bx,bx ! push ds
	    mov ax,cs ! mov ds,ax
	    call cprnt1 ! pop ds
prr1:	ret

prtyp:  mov bh,3 ! jmps prn1
prnam:	mov bh,8
prn1:	mov bl,' '
	mov si,u_conccb
	mov di,rlr
	cmp [si],di ! jne prr1
cprnt1:	    mov cx,f_conprint ! jmps jos

flclse:
	mov cx,f_fclose ! mov dx,offset cli_fcb
	jmps fo1
flopn:
	mov cx,f_fopen
	mov si,offset cli_fcb
	or byte ptr fcb_name+5[si],080h		;f6`=open read-only
	mov dx,si
fo1:	push es ! call osif ! pop es ! ret

cli_sync:mov cx,f_sync
	jmps mx1

cli_unsync: mov cx,f_unsync
mx1:	mov bx,offset cli_spb
jos:	jmp osif

pfn:	mov dx,offset cli_pcb ! mov cx,f_parsefilename
	jmps jos

conasn:	mov cx,f_conassign ! mov dx,offset cli_acb
	jmps jos

questr		db	' Msg Qued',0
userstr		db	'(User 0)',0
