$title	('MP/M 1.1 Command Line Interpreter')
	name	cli
	cseg
;cli:
;do;

;/*
;  Copyright (C) 1979,1980
;  Digital Research
;  P.O. Box 579
;  Pacific Grove, CA 93950
;
;  Revised:
;    18 Jan 80 by Thomas Rolander
;*/

;$include (common.lit)
;$nolist
;$include (proces.lit)
;$nolist
;$include (queue.lit)
;$nolist
;$include (fcb.lit)
;$nolist
;$include (xdos.lit)
;$nolist
;$include (memmgr.lit)
;$nolist
;$include (memmgr.ext)
;$nolist
;$include (xdos.ext)
;$nolist
;$include (bdos.ext)
;$nolist
;$include (bdosi.ext)
;$nolist
;$include (datapg.ext)
;$nolist

;  declare stktbl (1) structure (loc (10) address) external;
	extrn	stktbl

;  declare pdtbl (1) structure (process$descriptor) external;
	extrn	pdtbl

;  declare console$attached (1) address external;
	extrn	cnsatt

;  declare rlr address external;
	extrn	rlr

;  declare rlrpd based rlr process$descriptor;

;  assign:
	extrn	assign
;    procedure (nameadr) byte external;
;      declare nameadr address;
;    end assign;

;  dispatch:
	extrn	dispatch
;    procedure external;
;    end dispatch;

;  parsefilename:
	extrn	parsefilename
;    procedure (pcb$address) address external;
;      declare pcb$address address;
;    end paresefilename;

;  makeq:
	extrn	makeq
;    procedure (qcbadr) byte external;
;      declare qcbadr address;
;    end makeq;

;  openq:
	extrn	openq
;    procedure (uqcbadr) byte external;
;      declare uqcbadr address;
;    end openq;

;  readq:
	extrn	readq
;    procedure (uqcbadr) byte external;
;      declare uqcbadr address;
;    end readq;

;  cwriteq:
	extrn	cwriteq
;    procedure (uqcbadr) byte external;
;      declare uqcbadr address;
;    end cwriteq;

;  detach:
	extrn	detach
;    procedure external;
;    end detach;

;  xbdos:
	extrn	xbdos
;    procedure (func,info) address external;
;      declare func byte;
;      declare info address;
;    end xbdos;

;  xdos:
	extrn	xdos
;    procedure (func,info) address external;
;      declare func byte;
;      declare info address;
;    end xdos;

;  endp:
	extrn	endp
;    procedure external;
;    end endp;

;  absrq:
	extrn	absrq
;    procedure (mdadr) byte external;
;      declare mdadr address;
;    end absrq;

;  relrq:
	extrn	relrq
;    procedure (mdadr) byte external;
;      declare mdadr address;
;    end relrq;

;  memfr:
	extrn	memfr
;    procedure (mdadr) byte external;
;      declare mdadr address;
;    end memfr;

;  printb:
	extrn	printb
;    procedure (msgadr);
;      declare msgadr address;
;    end printb;

;  open:
	extrn	open
;    procedure (fcbadr) byte;
;      declare fcbadr address;
;    end open;

;  readbf:
	extrn	readbf
;    procedure (fcbadr) byte;
;      declare fcbadr address;
;    end readbf;

;  setdma:
	extrn	setdma
;    procedure (dmaadr) external;
;      declare dmaadr address;
;    end setdma;

	dseg
;  declare reserved$for$disk (3) byte;
	ds	3
;  declare buffer (128) byte;
buffer:	ds	128

;  declare pname (10) byte initial (
;    0,'        ',0);
pname:
	db	0
	db	'        '
	db	0

;/*
;  CLI Process Data Segment
;*/
;  declare cli$pd process$descriptor public
;    initial (0,rtr$status,199,.cli$entrypt,
;             'c'+80h,'li     ',0,0ffh,0,0,.buffer,0);
clipd:
	public	clipd
	extrn	attchpd
	dw	attchpd	; pl
	db	0	; status
	db	199	; priority
	dw	clientrypt	; stkptr
	db	'c'+80H,'li     '	; name
	db	$-$	; console
	db	0ffh	; memseg (system)
	dw	$-$	; b
	dw	$-$	; thread
	dw	buffer	; disk set DMA
	db	$-$	; disk select / user code
	dw	$-$	; dcnt
	db	$-$	; searchl
	dw	$-$	; searcha
	ds	2	; drvact
	ds	20	; registers
	ds	2	; scratch

;  declare cli$stk (13) address
;    initial (restarts,.cli);
clistk:
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
clientrypt:
	dw	cli

;  declare cli$lqcb
;    structure (lqueue,
;               buf (131) byte) public
;    initial (0,'CliQ    ',129,1);
clilqcb:
	public	clilqcb
	dw	$-$	; ql
	db	'CliQ    '	; name
	dw	129	; msglen
	dw	1	; nmbmsgs
	dw	$-$	; dqph
	dw	$-$	; nqph
	dw	$-$	; mh
	dw	$-$	; mt
	dw	$-$	; bh
	ds	131	; buf (131) byte

;  declare CLIQ userqcbhead
;    initial (.cli$lqcb,.field);
cliq:
	dw	clilqcb	; pointer
	dw	field	; msgadr

;  declare pcb structure (
;    field$adr address,
;    fcb$adr address );
pcb:
	ds	2	; fieldadr
	ds	2	; fcbadr

;  declare field (129) byte;
field:	ds	129
;  declare disk$select byte at (.field);
diskselect	equ	field
;  declare console byte at (.field(1));
console	equ	field+1
;  declare command$tail (1) byte at (.field(2));
commandtail	equ	field+2

;  declare fcb fcb$descriptor;
fcb:
	db	$-$	; et
	db	'        '	; fn
	db	'   '	; ft
	db	$-$	; ex
	dw	$-$	; nu
	db	$-$	; rc
	ds	16	; dm
	db	$-$	; nr

;  declare cusp$uqcb userqcb initial (
;    0,.field,'$$$$$$$$');
cuspuqcb:
	dw	$-$	; pointer
	dw	field	; msgadr
	db	'$$$$$$$$'	; name

;  declare nxt$chr$adr address;
nxtchradr:
	ds	2

;  declare ret byte;

;  declare md memory$descriptor;
md:
	db	$-$	; base
	db	$-$	; size
	db	$-$	; attrib
	db	$-$	; bank

;  declare pdadr address;
pdadr:	ds	2
;  declare pd based pdadr process$descriptor;

;  declare (base,top) address;
base:	ds	2
top:	ds	2

;  declare (i,j) address;
i:	ds	2
j:	ds	2

;  declare (mask,prl,ok,notdone) byte;
mask:	ds	1
prl:	ds	1
ok:	ds	1
notdone:	ds	1

;  declare sector$size literally '0080H';

;  declare user$priority literally '200';

;  declare segment$bottom address;
segmentbottom:
	ds	2

;  declare offset address;
offset:	ds	2

;  declare data$size address;
datasize:
	ds	2

;  declare mem$pointer address;
mempointer:
	ds	2
;  declare instr based mem$pointer byte;
;  declare location based mem$pointer address;
;  declare array based mem$pointer (1) byte;

;  declare loc3 byte at (0003H);
loc3	equ	0003h

;  declare bitmap$adr address;
bitmapadr:
	ds	2
;  declare bitmap based bitmap$adr (1) byte;

;  declare prl$code$adr address;
prlcodeadr:
	ds	2
;  declare prl$code based prl$code$adr (1) byte;

;  declare prlen address;
prlen:
	ds	2

	cseg
;  declare tfcb$default (38) byte data (
tfcbdefault:
	db	0,'        ','   '
	db	0,0,0,0
	db	0,'        ','   '
	db	0,0,0,0
	db	0,0,0,0,0,0
;      /* setup tfcb:    005CH - 005CH = 0
;                        005DH - 0067H = ' '
;                        0068H - 006BH = 0
;               tfcb+16: 006CH - 006CH = 0
;                        006DH - 0077H = ' '
;                        0078H - 007BH = 0
;                        007CH - 007FH = 0
;               tbuff:   0080H - 0081H = 0  */

plderr:
	db	'Prg ld err'
	db	'$'

abstpana:
	db	'Abs TPA not free'
	db	'$'

insufrm:
	db	'Reloc seg not free'
	db	'$'

badprlhr:
	db	'Bad PRL hdr rec'
	db	'$'

prltype:
	db	'PRL'

comtype:
	db	'COM'

fltypblnk:
	db	'Blnk file type rqd'
	db	'$'

quefull:
	db	'Queue full'
	db	'$'

illegal:
	db	'Bad entry'
	db	'$'

;  pmove:
pmove:
	; BC = COUNT, DE = SOURCE ADR, HL = DEST ADR
;    procedure (n,s$adr,d$adr);
;      declare (n,s$adr,d$adr) address;
;      declare s based s$adr byte;
;      declare d based d$adr byte;

;      n = n + 1;
;      do while (n := n - 1) <> 0;
@38:
	MOV	A,B
	ORA	C
	RZ
;        if s >= 'a' and s <= 'z'
	LDAX	D
	MOV	M,A
	CPI	'a'
	JC	@2
	CPI	'z'+1
	JNC	@2
;          then d = s and 101$1111b;  /* force upper case */
	ANI	5FH
	MOV	M,A
;          else d = s;
@2:
;        s$adr = s$adr + 1;
	INX	D
;        d$adr = d$adr + 1;
	INX	H
;      end;
	DCX	B
	JMP	@38
;    end pmove;

;  setup$base$page:
setupbasepage:
;    procedure;

;      /* place a jump to xdos in the top three bytes
;         of the memory segment                       */
;      base,
;      mem$pointer = top - 3;
	LHLD	TOP
	DCX	H
	DCX	H
	DCX	H
	SHLD	BASE
;      instr = 0C3H;
	MVI	M,0C3H
;      mem$pointer = mem$pointer + 1;
	INX	H
;      location = .xbdos;

;      /* place a jump to the termination procedure (ENDP)
;         at the first three bytes of the memory segment  */
	LXI	B,XBDOS
	MOV	M,C
	INX	H
	MOV	M,B
;      if (mem$pointer := segment$bottom) <> 0000H then
	LHLD	SEGMENTBOTTOM
	MOV	A,H
	ORA	L
	JZ	@3
;      do;
;        instr = 0C3H;
	MVI	M,0C3H
;        mem$pointer = mem$pointer + 1;
	INX	H
;        location = .endp;
	LXI	B,ENDP
	MOV	M,C
	INX	H
	MOV	M,B
;      end;

;      /* place a jump to the mem segment top - 3 into
@3:
;         the normal bdos jump at mem segment 0005H    */
;      mem$pointer = segment$bottom + 5;
	LXI	D,5H
	LHLD	SEGMENTBOTTOM
	DAD	D
;      instr = 0C3H;
	MVI	M,0C3H
;      mem$pointer = mem$pointer + 1;
	INX	H
;      location = base;
	XCHG
	LHLD	BASE
	XCHG
	MOV	M,E
	INX	H
	MOV	M,D
;    end setup$base$page;
	RET

;  parse$command$tail:
parsecommandtail:
;    procedure;

;      call pmove (128-(nxt$chr$adr-.command$tail),nxt$chr$adr,
	LHLD	NXTCHRADR
	XCHG
	MOV	A,E
	SUI	LOW(COMMANDTAIL)
	MOV	B,A
	MVI	A,80H
	SUB	B
	LXI	B,0014H
	LHLD	PDADR
	DAD	B
	MOV	C,M
	INX	H
	MOV	H,M
	MOV	L,C
	PUSH	H
	INX	H
	MOV	C,A
	MVI	B,0
	CALL	PMOVE
	POP	H
	PUSH	H
;                 (mem$pointer := pd.disk$set$dma+1));
;      j = 0;
	MVI	B,0FFH
;      do while instr <> 0;
@40:
	INX	H
	INR	B
	MOV	A,M
	ORA	A
	JNZ	@40
;        mem$pointer = mem$pointer + 1;
;        j = j + 1;
;      end;
;      mem$pointer = pd.disk$set$dma;
	POP	H
;      instr = j;
	MOV	M,B
;      pcb.field$adr = nxt$chr$adr;
	LHLD	NXTCHRADR
	SHLD	PCB
;      pcb.fcb$adr = segment$bottom + 5CH;
	LXI	D,5CH
	LHLD	SEGMENTBOTTOM
	DAD	D
	SHLD	PCB+2H
;      if (nxt$chr$adr := xdos (parse$fname,.pcb)) <> 0FFFFH then
	LXI	B,PCB
	CALL	PARSEFILENAME
	SHLD	NXTCHRADR
	INX	H
	MOV	A,H
	ORA	L
	RZ
;      /* valid first file name in command tail */
;      do;
;        if nxt$chr$adr <> 0 then
	DCX	H
	MOV	A,H
	ORA	L
	RZ
;        /* parse second file name in command tail */
;        do;
;          pcb.field$adr = nxt$chr$adr + 1;
	INX	H
	SHLD	PCB
;          pcb.fcb$adr = segment$bottom + 6CH;
	LXI	D,6CH
	LHLD	SEGMENTBOTTOM
	DAD	D
	SHLD	PCB+2H
;          nxt$chr$adr = xdos (parse$fname,.pcb);
	LXI	B,PCB
	CALL	PARSEFILENAME
	SHLD	NXTCHRADR
;        end;
;      end;
;    end parse$command$tail;
	RET

;  relocate:
relocate:
;    procedure;

;      /* offset by base of reloc memseg */
;      offset = md.base;
;      /* bitmap directly follows last byte of code */
	LDA	MD
	MOV	B,A
;      bitmap$adr = .prl$code + prlen;
	LHLD	PRLEN
	XCHG
	LHLD	PRLCODEADR
	PUSH	H
	DAD	D
;      prlen = prlen - 1;
;      j = 0;
;      mask = 80H;
;      /* loop through entire bit map */
	MVI	C,80H
;      do i = 0 to prlen;
	; B = OFFSET, C = MASK, DE = PRLEN, HL = BITMAPADR
	; TOS = PRLCODEADR
@42:
;        if (bitmap(j) and mask) <> 0 then
	MOV	A,M
	ANA	C
	XTHL
	JZ	@6
;        /* offset the byte where a bitmap bit is on */
;        do;
;          prl$code(i) = prl$code(i) + offset;
	MOV	A,M
	ADD	B
	MOV	M,A
;        end;
@6:
	INX	H
	XTHL
;        /* move mask bit one position to the right */
;        if (mask := shr(mask,1)) = 0 then
	MOV	A,C
	RAR
	MOV	C,A
	JNC	@7
;        /* re-initialize mask and get next bitmap byte */
;        do;
;          mask = 80H;
	MVI	C,80H
;          j = j + 1;
	INX	H
;        end;
@7:
;      end;
	DCX	D
	MOV	A,D
	ORA	E
	JNZ	@42
;    end relocate;
	POP	H
	RET

;  pd$init:
pdinit:
;    procedure;

;      pd.pl = 0;
	LHLD	PDADR
	XRA	A
	MOV	M,A
	INX	H
	MOV	M,A
;      pd.status = rtr$status;
	INX	H
	MOV	M,A
;      pd.priority = user$priority;
	INX	H
	MVI	M,0C8H
	XCHG
;      pd.stkptr = .stktbl(rlrpd.memseg).loc(18);
	LXI	B,000FH
	LHLD	RLR
	DAD	B
	MOV	A,M
	LXI	B,0014H
	LXI	H,STKTBL-4
	INR	A
@MPM0:
	DAD	B
	DCR	A
	JNZ	@MPM0
	XCHG
	INX	H
	MOV	M,E
	INX	H
	MOV	M,D
;      call pmove (8,.fcb.fn,.pd.name);
	LXI	B,8H
	INX	H
	LXI	D,FCB+1H
	CALL	PMOVE
;      pd.console = rlrpd.console;
	XCHG
	LXI	B,000EH
	LHLD	RLR
	DAD	B
	MOV	A,M
	STAX	D
;      pd.memseg = rlrpd.memseg;
	INX	D
	INX	H
	MOV	A,M
	STAX	D
;      segment$bottom = shl(double(md.base),8);
	LDA	MD
	MOV	H,A
	MVI	L,0
	SHLD	SEGMENTBOTTOM
;      pd.disk$set$dma = segment$bottom + 0080H;
	LXI	D,0080H
	DAD	D
	XCHG
	LXI	B,0014H
	LHLD	PDADR
	DAD	B
	MOV	M,E
	INX	H
	MOV	M,D
;      pd.disk$slct = rlrpd.disk$slct;
	INX	H
	XCHG
	LXI	B,0016H
	LHLD	RLR
	DAD	B
	MOV	A,M
	STAX	D
;    end pd$init;
	RET

;  load:
load:
;    procedure;

;      /* obtain proc dscrptr adr from memsegtbl index */
;      pdadr = .pdtbl(rlrpd.memseg);

;      /* make dispatch call to force memory selection */
	LXI	B,0FH
	LHLD	RLR
	DAD	B
	MOV	A,M
	LXI	H,PDTBL-34H
	LXI	B,0034H
	INR	A
@MPM1:
	DAD	B
	DCR	A
	JNZ	@MPM1
	SHLD	PDADR
;      ret = xdos (dispatch,0);
	CALL	DISPATCH

;      /* initialize process descriptor */
;      call pd$init;

	CALL	PDINIT
;      base = segment$bottom + 0100H;
	LXI	D,100H
	LHLD	SEGMENTBOTTOM
	DAD	D
	SHLD	BASE
;      prl$code$adr = base;

;      /* setup stack */
	SHLD	PRLCODEADR
;      stktbl(pd.memseg).loc(19) = .endp;
	LXI	B,0FH
	LHLD	PDADR
	DAD	B
	MOV	A,M
	LXI	B,0014H
	LXI	H,STKTBL-2
	INR	A
@MPM2:
	DAD	B
	DCR	A
	JNZ	@MPM2
	LXI	B,ENDP
	MOV	M,C
	INX	H
	MOV	M,B
;      stktbl(pd.memseg).loc(18) = base;
	DCX	H
	DCX	H
	XCHG
	LHLD	BASE
	XCHG
	MOV	M,D
	DCX	H
	MOV	M,E
;      do i = 0 to 8;
	MVI	B,16
@44:
;        stktbl(pd.memseg).loc(i) = 0C7C7H;
	DCX	H
	MVI	M,0C7H
;      end;
	DCR	B
	JNZ	@44

;      top = segment$bottom + shl(double(md.size),8);
	LDA	MD+1H
	MOV	D,A
	MVI	E,0
	LHLD	SEGMENTBOTTOM
	DAD	D
	SHLD	TOP
;      ok = false;
;      notdone = true;

;      /* read COM or PRL+bitmap file into memory */
;      do while notdone;
@46:
;        if base = top then
	LHLD	BASE
	XCHG
	LHLD	TOP
	MOV	A,E
	CMP	L
	JNZ	@8
	MOV	A,D
	CMP	H
	JNZ	@8
;        do;
;          notdone = false;
;          if prl then ok = true;
	LDA	PRL
	RAR
	JC	@47
;          else
;          do;
;            call set$dma (.buffer);
	LXI	B,BUFFER
	CALL	SETDMA
;            if readbf (.fcb) = 1 then ok = true;
	LXI	B,FCB
	CALL	READBF
	DCR	A
	JZ	@47
	JMP	@15
;          end;
;        end;
@8:
;        else
;        do;
;          call set$dma (base);
	LHLD	BASE
	MOV	B,H
	MOV	C,L
	LXI	D,80H
	DAD	D
	SHLD	BASE
	CALL	SETDMA
;          base = base + sector$size;
;          if (ret := readbf (.fcb)) <> 0 then
	LXI	B,FCB
	CALL	READBF
	ORA	A
	JZ	@46
;          do;
;            notdone = false;
;            if ret = 1 then ok = true;
	DCR	A
	JNZ	@15
;          end;
;        end;
;      end;
@47:

;      /* free drives */
;      ret = xdos (39,0ffffh);
	mvi	c,39
	lxi	d,0ffffh
	call	xbdos
;      if ok then
;      /* file read with no errors */
;      do;
;        if prl then
	LDA	PRL
	RAR
;        /* page relocatable, do the relocation */
;        do;
;          call relocate;
	CC	RELOCATE
;        end;

;        call pmove (38,.tfcb$default,segment$bottom+5CH);
	LXI	B,26H
	LXI	D,5CH
	LHLD	SEGMENTBOTTOM
	DAD	D
	LXI	D,TFCBDEFAULT
	CALL	PMOVE
;        if nxt$chr$adr <> 0 then
	LHLD	NXTCHRADR
	MOV	A,H
	ORA	L
;        /* parse the command tail */
;        do;
;           call parse$command$tail;
	CNZ	PARSECOMMANDTAIL
;        end;

;        /* setup base page of memory segment */
;        call setup$base$page;

	CALL	SETUPBASEPAGE
;        /* attach the console to the process to be created */
;        console$attached(pd.console) = pdadr;

;        /* create - start the process */
	LHLD	PDADR
	XCHG
	LXI	H,000EH
	DAD	D
	MOV	C,M
	MVI	B,0
	LXI	H,cnsatt	; CONSOLEATTACHED
	DAD	B
	DAD	B
	MOV	M,E
	INX	H
	MOV	M,D
;        rlrpd.memseg = 0ffh; /* set clipd.memseg back to system */
	LXI	B,0FH
	LHLD	RLR
	DAD	B
	MVI	M,0FFH
;        ret = xdos (create,pdadr);

	MVI	C,90H
	JMP	XDOS
;      end; /* of successful file read */
@15:
;      else
;      /* file read errors */
;      do;
;        /* free the allocated memory segment */
;        call mem$fr (.md);
	LXI	B,MD
	CALL	MEMFR
;        rlrpd.memseg = 0ffh; /* set clipd.memseg back to system */
	LXI	B,0FH
	LHLD	RLR
	DAD	B
	MVI	M,0FFH
;        call print$b (.(
	LXI	B,plderr
	JMP	PRINTB
;          'Program load error.','$'));
;      end;
;    end load;

;  load$COM:
loadcom:
;    procedure;

;      md.base = 00H;
;      /* make absolute memory request */
	LXI	B,MD
	XRA	A
	STAX	B
;      if abs$rq (.md) = 0 then
	CALL	ABSRQ
	ORA	A
;      /* successful memory request */
;      do;
;        /* load and create process */
;        call load;
	JZ	LOAD
;      end;
;      else
;      /* unsuccessful memory request */
;      do;
;        call print$b (.('Absolute ',
	LXI	B,abstpana
	JMP	PRINTB
;          'TPA is not currently available.','$'));
;      end;
;    end load$COM;

;  load$PRL:
loadprl:
;    procedure;

;      ok = false;
;      /* read in first record, contains code size
;         and data size information                */
;      if readbf (.fcb) = 0 then
	LXI	B,FCB
	CALL	READBF
	ORA	A
	JNZ	@21
;      do;
;        /* obtain code length */
;        mem$pointer = .buffer(1);
	LXI	H,BUFFER+1H
;        prlen = location;

;        /* obtain data length */
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG
	SHLD	PRLEN
;        mem$pointer = mem$pointer + 3;
	XCHG
	INX	H
	INX	H
;        data$size = location;

;        /* compute size of memory segment needed */
	MOV	E,M
	INX	H
	MOV	D,M
;        md.size = high(prlen+0FFH)
;                 + high(data$size+0FFH)
;                 + shr(prlen,11)
;                 + 1;

	LXI	B,0FFH
	LHLD	PRLEN
	DAD	B
	MOV	A,H
	XCHG
	DAD	B
	ADD	H
	INR	A
	MOV	B,A
	LDA	PRLEN+1
	ANI	0F8H
	RRC
	RRC
	RRC
	ADD	B
	STA	MD+1H
;        /* ignore next sector */
;        if readbf (.fcb) = 0 then
	LXI	B,FCB
	CALL	READBF
	ORA	A
	JNZ	@22
;        do;
;          /* make relocatable memory request */
;          if rel$rq(.md) = 0 then
	LXI	B,MD
	CALL	RELRQ
	ORA	A
;          /* successful memory request */
;          do;
;            /* load and create process */
;            call load;
	JZ	LOAD
;            return;
;          end;
;          else
;          /* unsuccessful memory request */
;          do;
;            call print$b (.(
;              'Insufficient relocatable memory to',
	LXI	B,insufrm
	JMP	PRINTB
;              ' load program.','$'));
;            return;
;          end;
@24:
;        end; /* of successful ignore record read */
@22:
;      end; /* of successful header record read */
@21:
;      call print$b (.(
	LXI	B,badprlhr
	JMP	PRINTB
;        'Bad PRL header record.','$'));
;    end load$PRL;

;  file$load$execute:
fileloadexecute:
;    procedure;

;      call set$dma (.buffer);
	LXI	B,BUFFER
	CALL	SETDMA
;      prl = true;
	LXI	H,PRL
	MVI	M,0FFH
;      if fcb.ft(0) = ' ' then
	LXI	H,FCB+9H
	MOV	A,M
	CPI	20H
	JNZ	@25
;      /* type must be left blank */
;      do;
;        call pmove (3,.('PRL'),.fcb.ft);
	MVI	M,'P'
	INX	H
	MVI	M,'R'
	INX	H
	MVI	M,'L'

;        /* first try for PRL file */
;        if open (.fcb) = 0FFH then
	LXI	B,FCB
	CALL	OPEN
	INR	A
	JNZ	LOADPRL
;        /* PRL file not found, try COM file */
;        do;
;          prl = false;
	LXI	H,PRL
	MVI	M,0H
;          call pmove (3,.('COM'),.fcb.ft);
	LXI	H,FCB+9H
	MVI	M,'C'
	INX	H
	MVI	M,'O'
	INX	H
	MVI	M,'M'
;          if open (.fcb) = 0FFH then
	LXI	B,FCB
	CALL	OPEN
	INR	A
	JNZ	LOADCOM
;          /* unsuccessful file open */
;          do;
;            call print$b (.(
	LXI	H,FCB+9H
@23:
	DCX	H
	MOV	A,M
	CPI	' '
	JZ	@23
	INX	H
	MVI	M,'?'
	INX	H
	MVI	M,'$'
	LXI	B,FCB+1H
	JMP	PRINTB
;              'No such file.','$'));
;            return;
;          end;
;        end;

;        /* successful file open */
;        if prl then
;        /* relocatable load */
;        do;
;          call load$PRL;
;        end;
;        else
;        /* COM file load */
;        do;
;          call load$COM;
;        end;
;      end; /* of blank file type */
@25:
;      else
;      do;
;      /* non-blank file type */
;        call print$b (.(
	LXI	B,fltypblnk
	JMP	PRINTB
;          'File type must not be specified.','$'));
;      end;
;    end file$load$execute;

;  queue$message:
queuemessage:
;    procedure boolean;

;      call pmove (8,.fcb.fn,.cusp$uqcb.name);
	LXI	B,8H
	LXI	H,CUSPUQCB+4H
	LXI	D,FCB+1H
	CALL	PMOVE
;      if xdos (open$queue,.cusp$uqcb) = 0 then
	LXI	B,CUSPUQCB
	CALL	openq
	ORA	A
	MVI	A,0
	RNZ
;      /* queue exists */
;      do;
;        call pmove (8,.fcb.fn,.pname(1));
	LXI	B,8H
	LXI	H,PNAME+1H
	LXI	D,FCB+1H
	CALL	PMOVE
;        /* assign the console to the process, if any,
;           associated with the queue. a console is
;           associated with a process if there is a
;           process with the same name as the queue.   */
;        ret = assign (.pname);

	LXI	B,PNAME
	CALL	ASSIGN
;        if nxt$chr$adr <> 0 then
	LHLD	NXTCHRADR
	MOV	A,H
	ORA	L
	JZ	@32
;        /* copy the command tail */
;        do;
;          call pmove (128-(nxt$chr$adr-.command$tail),
	LHLD	NXTCHRADR
	XCHG
	MOV	A,E
	INX	D
	SUI	LOW(COMMANDTAIL)
	MOV	B,A
	MVI	A,80H
	SUB	B
	MOV	C,A
	MVI	B,0
	LXI	H,FIELD+2H
	CALL	PMOVE
;            nxt$chr$adr+1,.field(2));
;        end;
	JMP	@33
@32:
;        else
;        /* put a <cr> in first field position */
;        do;
;          field(2) = 0dh;
	LXI	H,FIELD+2H
	MVI	M,0DH
;        end;
@33:

;        /* conditionally write the message to the queue */
;        if xdos (cond$write$queue,.cusp$uqcb) <> 0 then
	LXI	B,CUSPUQCB
	CALL	cwriteq
	ORA	A
;        /* write failed, buffer not available */
;        do;
;          call print$b (.(
	LXI	B,quefull
	CNZ	PRINTB
;            'Queue full.','$'));
;        end;
@34:
;        return true;
	MVI	A,0FFH
	RET
;      end; /* of successful queue open */
;      /* queue open failed */
;      return false;
;    end queue$message;


;/*
;  cli:
;*/

;  cli:
cli:
;    procedure;

;      ret = xdos (make$queue,.cli$lqcb);

	LXI	B,CLILQCB
	CALL	makeq
;      do forever;
@48:
;        ret = xdos (read$queue,.CLIQ);
	LXI	B,CLIQ
	CALL	readq
;        pname(0),
;        rlrpd.console = console;
	LDA	CONSOLE
	STA	PNAME
	LHLD	RLR
	XCHG
	LXI	H,000EH
	DAD	D
	MOV	M,A
;        rlrpd.disk$slct = disk$select;
	LXI	H,16H
	DAD	D
	LDA	DISKSELECT
	MOV	M,A
;        pcb.field$adr = .command$tail;
	LXI	H,COMMANDTAIL
	SHLD	PCB
;        pcb.fcb$adr = .fcb;
	LXI	H,FCB
	SHLD	PCB+2H
;        if (nxt$chr$adr := xdos (parse$fname,.pcb)) <> 0FFFFH then
	LXI	B,PCB
	CALL	parsefilename
	SHLD	NXTCHRADR
	INX	H
	MOV	A,H
	ORA	L
	JZ	@35
;        /* legitimate queue or file name entered */
;        do;
;          fcb.nr = 0;
;          /* test for message to be queued */
	LXI	H,FCB+20H
	MVI	M,0H
;          if not queue$message
	CALL	QUEUEMESSAGE
	RAR
	JC	@37
;          then
;          /* file is to be loaded and executed */
;          do;
;            call file$load$execute;
	CALL	FILELOADEXECUTE
;          end;
;        end;
	JMP	@37
@35:
;        else
;        /* illegitimate queue or file name */
;        do;
;          call print$b (.(
	LXI	B,illegal
	CALL	PRINTB
;            'Illegal entry.','$'));
;        end;
@37:

;        /* detach the console from CLI, if still attached */
;        ret = xdos (detach,0);
	LXI	B,CLIPD
	CALL	DETACH
;        /* free drives, if still accessed */
;        ret = xdos (39,0ffffh);
	mvi	c,39
	lxi	d,0ffffh
	call	xbdos
;      end; /* of forever */
	JMP	@48

;    end cli; /* procedure */

;end cli;
	END
