$title	('MP/M 1.1 Parse Filename')
	name	parse
	cseg
;parse:
;do;

;$include (copyrt.lit)
;/*
;  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 (queue.lit)
;$nolist
;$include (xdos.lit)
;$nolist
;$include (xdos.ext)
;$nolist

;  readq:
	extrn	readq
;    procedure (uqcbadr) byte external;
;      declare uqcbadr address;
;    end readq;

;  writeq:
	extrn	writeq
;    procedure (uqcbadr) byte external;
;      declare uqcbadr address;
;    end writeq;

;  xdos:
	extrn	xdos
;    procedure (func,info) address external;
;      declare func byte;
;      declare info address;
;    end xdos;

	dseg
;/*
;  Parse Queue Data Segment
;*/
;  declare parse$cqcb structure (cqueue,pdadr address) public
;    initial (0,'MXParse ',0,1);
	public	parsecqcb
parsecqcb:
	dw	$-$	; ql
	db	'MXParse '	; name
	dw	0	; msglen
	dw	1	; nmbmsgs
	dw	$-$	; dqph
	dw	$-$	; nqph
	dw	$-$	; msgin
	dw	$-$	; msgout
	dw	$-$	; msgcnt

	dw	$-$	; pdadr

;  declare parse$mutex address public
;    initial (.parse$cqcb);
parsemutex:
	public	parsemutex
	dw	parsecqcb	; pointer
	cseg

del:
	db	0dh,' =.:<>_[],'

;  /*
;    parse:
;  */

parse:
;  parse:
;    procedure (pcb$adr) address;
	dseg
;    declare pcb$adr address;
pcbadr:	ds	2
;    declare pcb based pcb$adr structure (
;      filename$adr address,
;      fcb$adr address      );
;    declare pcb$filename$adr address;
pcbfilenameadr:
	ds	2
;    declare pcb$fcb$adr address;
pcbfcbadr:
	ds	2
;    declare filename based pcb$filename$adr (1) byte;
filename	equ	pcbfilenameadr+1
;    declare fcb based pcb$fcb$adr (1) byte;
fcb	equ	pcbfcbadr+1

;    declare
;      /* return conditions */
;      endline literally '00000H',
;      badfile literally '0FFFFH',
;      /* useful literals */
;      disk    literally 'fcb(0)',
;      fcbname literally '8',  /* end of name */
;      fcbtype literally '11', /* end of type field */
;      fcbsize literally '16'; /* partial size of fcb */

;    declare char byte; /* global temp for current char */
char:	ds	1
;    declare fnp  byte; /* index into file name buffer */
fnp:	ds	1
;    declare fnlen byte;
fnlen:	ds	1
	cseg

;    /* initialize local bases */
;    pcb$filename$adr = pcb.filename$adr;
	LDAX	B
	MOV	L,A
	INX	B
	LDAX	B
	MOV	H,A
	SHLD	PCBFILENAMEADR
;    pcb$fcb$adr      = pcb.fcb$adr;
;    /* initialize file control block to empty */
	INX	B
	LDAX	B
	MOV	L,A
	INX	B
	LDAX	B
	MOV	H,A
	SHLD	PCBFCBADR
;    char  = ' ';
	LXI	H,CHAR
	MVI	M,20H
;    fnlen  = 0;
	LXI	H,FNLEN
	MVI	M,0H
;    fnp   = -1;
	DCX	H
	MVI	M,0FFH
;    do while fnlen < fcbsize-1;
@24:
	LDA	FNLEN
	CPI	0FH
	JNC	@25
;      if fnlen = fcbtype then char = 0;
	SUI	0BH
	JNZ	@4
	LXI	H,CHAR
	MOV	M,A
@4:
;      call putchar;
	CALL	PUTCHAR
;    end;
	JMP	@24
@25:
;    disk = 0;
;    /* scan next name */
	LHLD	PCBFCBADR
	MVI	M,0H
;    do forever;
@26:
;    /* deblank command buffer */
;      call gnc;
	CALL	GNC	; char left in A
;      do while char = ' ';
@28:
	CPI	20H
	JZ	@26
;        call gnc;
;      end;
;      if delimiter then return badfile;
	CALL	DELIMITER
	RAR
	JC	@8A
;      fnlen = 0;
	LXI	H,FNLEN
	MVI	M,0H
;      do while not delimiter;
@30:
	CALL	DELIMITER
	RAR
	JC	@31
;        if fnlen >= fcbname then /* error, file name too long */
	LDA	FNLEN
	CPI	8H
	JC	@6
;          return badfile;
@8A:
	LXI	H,0FFFFH
	RET

@6:
;        if char = '*' then call fillq(fcbname); else call putchar;
	LDA	CHAR
	CPI	2AH
	JNZ	@7
	MVI	C,8H
	CALL	FILLQ
	JMP	@8
@7:
	CALL	PUTCHAR
@8:
;        call gnc;
	CALL	GNC
;      end;
	JMP	@30
@31:

;      /* check for disk name */
;      if char = ':' then
	LDA	CHAR
	CPI	3AH
	JNZ	@9
;      do;
;        if not (disk = 0 and fnlen = 1) then
	LHLD	PCBFCBADR
	MOV	A,M
	ORA	A
	JNZ	@8A
	LDA	FNLEN
	DCR	A
	JNZ	@8A
;          return badfile;
;        /* must be a disk name */
;        if (disk := fcb(1) - 'A' + 1) > 26
;          /* invalid disk name */
	LHLD	PCBFCBADR
	INX	H
	MOV	A,M
	SUI	41H
	INR	A
	DCX	H
	MOV	M,A
	CPI	27
	JNC	@8A
;          then return badfile;
;          /* valid disk name replace space in name */
;          else fcb(fnlen) = ' ';
	LHLD	FNLEN
	MVI	H,0
	XCHG
	LHLD	PCBFCBADR
	DAD	D
	MVI	M,20H
;      end;
	JMP	@26
@9:
;      else
;      do;
;        /* char is not ':', so file name is set. scan remainder */
;        /* at least one char scanned */
;        fnlen = fcbname;
	LXI	H,FNLEN
	MVI	M,8H
;        if char = '.' then /* scan file type */
	CPI	2EH
	JNZ	@14
;        do;
;          call gnc;
	CALL	GNC
;          do while not delimiter;
@32:
	CALL	DELIMITER
	RAR
	JC	@33
;            if fnlen >= fcbtype then
	LDA	FNLEN
	CPI	0BH
	JC	@15
;              /* error, type field too long */
;              return badfile;
	LXI	H,0FFFFH
	RET
@15:
;            if char = '*'
	LDA	CHAR
	CPI	2AH
	JNZ	@16
;              then call fillq(fcbtype);
	MVI	C,0BH
	CALL	FILLQ
	JMP	@17
@16:
;              else call putchar;
	CALL	PUTCHAR
@17:
;              call gnc;
	CALL	GNC
;          end;
	JMP	@32
@33:
	LDA	CHAR
;        end;
@14:

;        if char = 0dh
	CPI	0DH
	LXI	H,0000H
;          then return endline;
	RZ
;          else return .filename(fnp);
	LHLD	FNP
	MVI	H,0
	XCHG
	LHLD	PCBFILENAMEADR
	DAD	D
	RET
;      end;
;    end; /* of forever */
;  end parse;

;    gnctran:
gnctran:
;      procedure(b) byte;
;        declare b byte;

;        if b < ' ' then return 0dh; /* all non-graphics */
	MOV	A,C
	CPI	20H
	MVI	A,0DH
	RC
;        /* translate alpha to upper case */
;        if b >= 'a' and b <= 'z' then
	MOV	A,C
	CPI	'a'
	RC
	CPI	'z'+1
	RNC
	ANI	5FH
	RET
;          b = b and 101$1111b; /* upper case */
;        return b;
;      end gnctran;

;    gnc:
gnc:
;      procedure;

;        char = gnctran(filename(fnp := fnp + 1));
	LXI	H,FNP
	INR	M
	MOV	C,M
	MVI	B,0
	LHLD	PCBFILENAMEADR
	DAD	B
	MOV	C,M
	CALL	GNCTRAN
	STA	CHAR
;      end gnc;
	RET

;    delimiter:
delimiter:
;      procedure byte;
;        declare i byte;
;        declare del(*) byte data
;          (0dh,' =.:<>_[],');

;        do i = 0 to last(del);
	MVI	C,11
	LXI	D,DEL
	LXI	H,CHAR
@20:
;          if char = del(i) then return true;
	LDAX	D
	SUB	M
	MVI	A,0FFH
	RZ
	INX	D
	DCR	C
	JNZ	@20
;        end;
;        return false;
	XRA	A
	RET
;      end delimiter;

;    putchar:
putchar:
;      procedure;

;        fcb(fnlen:=fnlen+1) = char;
;        /* can check here for ambig ref's "char = '?'" */
	LXI	H,FNLEN
	INR	M
	MOV	C,M
	MVI	B,0
	LHLD	PCBFCBADR
	DAD	B
	LDA	CHAR
	MOV	M,A
;      end putchar;
	RET

;    fillq:
fillq:
;      procedure(len);
;      /* fill current name or type with question marks */

;        declare len byte;

;        char = '?'; /* question mark */
	LXI	H,CHAR
	MVI	M,3FH
;        do while fnlen < len;
@22:
	LDA	FNLEN
	CMP	C
	RNC
;          call putchar;
	PUSH	B
	CALL	PUTCHAR
	POP	B
;        end;
	JMP	@22
;      end fillq;

;/*
;  parse$filename:
;*/

;  parse$filename:
parsefilename:
	PUSH	B
;    procedure (pcb$adr) address reentrant public;
	public	parsefilename
;      declare pcb$adr address;
;      declare nxt$chr$adr address;
;      declare ret byte;

;      ret = xdos (read$queue,.parse$mutex);
	LXI	B,PARSEMUTEX
	CALL	READQ
;      nxt$chr$adr = parse (pcb$adr);
	POP	B
	CALL	PARSE
	PUSH	H
;      ret = xdos (write$queue,.parse$mutex);
	LXI	B,PARSEMUTEX
	CALL	WRITEQ
;      return nxt$chr$adr;
	POP	H
	RET
;    end parse$filename;

;end parse;
	END
