;MACROS LIBRARY FOR CP/M ROUTINE SIMULATION   10/15/80

;CONTAINS:
;	1)   INBUF    - DUPLICATES READ BUFFER ROUTINE
;			SAME AS CP/M FUNCTION 10, BUT DOES
;			NOT USE CTRL-C (REASON FOR ROUTINE).
;			DOES ALLOW CONTROLS U, R, E, AND H (BACKSPACE).
;			OUTPUTS BELL IF INPUT GREATER THAN BUFFER
;	2)   CMDLINE  - PARSES A CP/M BUFFER INTO FORMAT SAME AS
;			CP/M COMMAND LINE.
;	3)   INLNCOMP - COMPARES STRINGS FOLLOWING CALL TO 'ILCOMP'
;		        TO STRING ADDRESSED BY DE REGS.
;	4)   MULTNAME - MULTI-FILE FILE ACCESS ROUTINE FROM
;			CP/M USERS GROUP.
;	5)   DIRLIST  -	LISTS DIRECTORY

INBUF	MACRO		;NO PARAMETERS USED.

	LOCAL START,INBUFO,INBUFA,DELETE,NODEL,ALERT
	LOCAL INBUFLT,CLEAR,CLEARL,INBUFR,RETYPE,BKSPC,PCRLF
	LOCAL CONIN,CONOUT,CONIN1,CONOUT1,NOUCASE,CTLRLP
	LOCAL CONSTAT,CONST1,CONINLP

	PUSH PSW
	PUSH H
	PUSH B
	PUSH D		;DE REGISTERS MUST BE PUSHED LAST
START	CALL CLEAR	;CLEAR THE BUFFER AREA
	POP D		;GET ADDRESS OF BUFFER ON RETRIES
	PUSH D		;RESTORE STACK
	XRA A
	INX D		;ADDRESS COUNT FIELD
	STAX D		;INITIALIZE WITH A ZERO IN COUNT BYTE
	INX D
	XCHG		;ADDRESS FIRST BUFFER BYTE WITH HL
INBUFA	CALL CONIN
	CPI 0DH		;IS IT A RETURN?
	JZ INBUFR	;IF SO, THEN RETURN
	CPI 7FH		;IS IT A DELETE?
	JZ DELETE
	CPI 8		;CTRL-H WILL BACKSPACE..
	JZ DELETE	;..OVER DELETED CHAR.
	CPI 'U'-40H	;IS IT A CTRL-U
	JZ INBUFO	;OUTPUT # CR LF AND START OVER
	CPI 'R'-40H	;CTRL-R RETYPES LINE
	JZ RETYPE
	CPI 'E'-40H
	JZ PCRLF
	CPI 20H		;NO CONTROL CHARACTERS OTHER..
	JC INBUFA	;..THAN ABOVE ALLOWED.
	MOV B,A		;SAVE INPUTTED CHARACTER
	XCHG		;SAVE HL IN DE
	POP H		;GET ADDRESS OF BUFFER IN HL
	PUSH H		;RESTORE STACK
	INX H		;ADDRESS COUNT BYTE
	INR M		;INCREASE COUNT BYTE
	DCX H		;ADDRESS MAXIMUM
	MOV A,M		;PUT MAXIMUM IN A
	INX H		;ADDRESS COUNT
	CMP M		;COMPARE COUNT TO MAXIMUM
	JC ALERT	;IF MAXIMUM, RING BELL AND WAIT FOR CR
	XCHG		;RESTORE BUFFER POINTER TO HL
	MOV M,B		;PUT INPUTTED CHARACTER IN BUFFER
	MOV A,B		;OUTPUT IT
	CALL CONOUT
	INX H		;BUMP POINTER
	JMP INBUFA	;GET NEXT CHARACTER

DELETE	XCHG		;SAVE BUFFER POINTER IN DE
	POP H		;ADDRESS BEGINNING OF BUFFER
	PUSH H		;RESTORE STACK
	INX H		;ADDRESS COUNT FIELD
	MOV B,A		;SAVE DELETE CHAR - 7FH OR 08H
	MOV A,M
	SUI 1		;DECREASE COUNT
	MOV M,A
	JC NODEL	;DON'T DELETE PAST BEGINING OF BUFFER.
	XCHG		;RESTORE BUFFER POINTER TO HL
	DCX H		;POINT TO LAST BYTE INPUTTED
	MOV A,B		;GET BACK EITHER 7FH OR 08H
	MOV B,M		;GET CHARACTER BEING DELETED
	MVI M,20H	;RESTORE BLANK
	CPI 8
	JZ BKSPC
	MOV A,B		;ECHO CHAR IF 7FH
	CALL CONOUT
	JMP INBUFA	;GET NEXT CHARACTER
NODEL	INR M		;DON'T LEAVE COUNT NEGATIVE
	XCHG		;RESTORE POINTER TO HL
	JMP INBUFA
BKSPC	CALL CONOUT	;TRUE ERASE IF 08H
	MVI A,20H
	CALL CONOUT
	MVI A,8
	CALL CONOUT
	JMP INBUFA

INBUFO	MVI A,'#'
	CALL CONOUT
	MVI A,0DH
	CALL CONOUT
	MVI A,0AH
	CALL CONOUT
	JMP START

RETYPE	POP D
	PUSH D
	INX D		;POINT TO CURRENT NUMBER..
	LDAX D		;..OF CHARACTERS.
	MOV B,A
	MVI A,'#'
	CALL CONOUT
	MVI A,0DH
	CALL CONOUT
	MVI A,0AH
	CALL CONOUT
	MOV A,B		;TEST IF ZERO INPUT
	ORA A
	JZ INBUFA
CTLRLP	INX D
	LDAX D
	CALL CONOUT
	DCR B
	JNZ CTLRLP
	JMP INBUFA
	
ALERT	MVI A,7
	CALL CONOUT
	DCR M
	XCHG
	JMP INBUFA

PCRLF	MVI A,0DH
	CALL CONOUT
	MVI A,0AH
	CALL CONOUT
	JMP INBUFA

INBUFR	MVI A,0DH
	CALL CONOUT
	MVI A,0AH
	CALL CONOUT
	POP D
	POP B
	POP H
	POP PSW
	RET

CLEAR	POP D		;ACCOUNTS FOR CALL
	POP H		;ADDRESS BUFFER IN HL
	PUSH H		;RESTORE..
	PUSH D		;..STACK
	MOV B,M		;SAVE MAXIMUM IN B
	INX H		;POINT TO FIRST..
	INX H		;..BUFFER BYTE.
	MVI A,20H
CLEARL	MOV M,A
	INX H
	DCR B
	JNZ CLEARL
	RET

CONIN	PUSH H ! PUSH D ! PUSH B
CONINLP	CALL CONSTAT
	ORA A
	JZ CONINLP
	CALL CONIN1
	CPI 61H		;CHANGE TO UPPER..
	JC NOUCASE	;..CASE SINCE CP/M..
	CPI 7BH		;..DOES THE SAME.
	JNC NOUCASE
	ANI 5FH
NOUCASE	POP B ! POP D ! POP H
	RET
CONIN1	LHLD 1
	LXI D,6
	DAD D
	PCHL

CONSTAT	PUSH H ! PUSH D ! PUSH B
	CALL CONST1
	POP B ! POP D ! POP H
	RET
CONST1	LHLD 1
	LXI D,3
	DAD D
	PCHL

CONOUT	PUSH H ! PUSH D ! PUSH B ! PUSH PSW
	CALL CONOUT1
	POP PSW ! POP B ! POP D ! POP H
	RET
CONOUT1	LHLD 1
	LXI D,9
	DAD D
	MOV C,A
	PCHL

	ENDM

CMDLINE	MACRO		;NO PARAMETERS USED

;LOADS A COMMAND LINE ADDRESSED BY DE REGISTERS (MAX # CHARACTERS IN LINE
;IN DE, NUMBER OF CHARS IN LINE IN DE+1, LINE STARTS IN DE+2) INTO FCB
;ADDRESSED BY HL REGISTERS. THE FCB SHOULD BE AT LEAST 33 BYTES IN LENGTH.
;THE COMMAND LINE BUFFER MUST HAVE A MAXIMUM LENGTH OF AT LEAST ONE MORE
;THAN THE GREATEST NUMBER OF CHARACTERS THAT WILL BE NEEDED.

	LOCAL CMDLINE, DEFDR, DONE, DRIVE, FILL1, FILL, FILL2, INIT, INITL1
	LOCAL INITL2, INITL3, INITL4, NAME1, NAME2, SCAN, TRANS, TSTNAM
	LOCAL TSTTYP, TSTTYPL, TYPE1, TYPE2, NAME2C


	PUSH PSW
	PUSH B
	PUSH D
	PUSH H

	CALL INIT	;FILLS FCBS WITH BLANKS AND NULLS

	XCHG		;GET START OF COMMAND LINE IN HL.
	INX H		;ADDRESS # BYTES IN CMD LINE.
	MOV E,M		;LOAD DE PAIR WITH # BYTES.
	MVI D,0
	INX H
	DAD D		;POINT TO BYTE AFTER LAST CHAR..
	MVI M,0DH	;..IN CMD LINE AND STORE DELIMITER.
	POP H		;RESTORE HL AND DE.
	POP D
	PUSH D
	PUSH H
	INX D		;ADDRESS START OF COMMAND.
	INX D

	CALL DRIVE

NAME1	MVI C,8		;TRANSFER FIRST FILENAME TO FCB.
	CALL TRANS
	CPI 0DH
	JZ DONE
	CPI 20H		;IF SPACE, THEN START OF..
	JZ NAME2	;..SECOND FILENAME.

TYPE1	POP H		;FILETYPE MUST BE AFTER..
	PUSH H		;..EIGHTH BYTE OF NAME.
	LXI B,9
	DAD B
	MVI C,3		;TRANSFER TYPE OF FIRST FILE
	CALL TRANS
	CPI 0DH
	JZ DONE

NAME2	LDAX D		;EAT MULTIPLE SPACES..
	CPI 20H		;..BETWEEN NAMES.
	JNZ NAME2C
	INX D
	JMP NAME2
	LDAX D
	CPI 0DH		;TEST IF FIRST NAME..
	JZ DONE		;..ONLY AND THEN SPACE.
NAME2C	POP H		;SECOND NAME STARTS IN 16TH BYTE.
	PUSH H		;POINT HL TO THIS BYTE.
	LXI B,16
	DAD B
	CALL DRIVE
	MVI C,8
	CALL TRANS
	CPI 0DH
	JZ DONE

TYPE2	POP H		;SECOND TYPE STARTS IN 25TH BYTE.
	PUSH H
	LXI B,25
	DAD B
	MVI C,3
	CALL TRANS

DONE	POP H
	PUSH H
	INX H		;POINT TO FIRST CHAR OF FIRST NAME IN FCB.
	CALL SCAN	;CHECK FOR * (AMBIGUOUS NAMES).
	POP H
	PUSH H
	LXI B,17	;POINT TO FIRST CHAR OF SECOND NAME IN FCB.
	DAD B
	CALL SCAN
	POP H
	POP D
	POP B
	POP PSW
	RET

; =============>>>  SUBROUTINES  <<===============

INIT	PUSH H		;INITIALIZES FCB WITH 1 NULL (FOR FIRST DRIVE),..
	PUSH B		;..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIVE),..
	MVI M,0		;..11 BLANKS, AND 4 NULLS.
	INX H
	MVI B,11
	MVI A,20H
	CALL INITFILL
	MVI B,5
	MVI A,0
	CALL INITFILL
	MVI B,11
	MVI A,20H
	CALL INITFILL
	MVI B,4
	MVI A,0
	CALL INITFILL
	POP B
	POP H
	RET

INITFILL
	MOV M,A
	INX H
	DCR B
	JNZ INITFILL
	RET

DRIVE	INX D		;CHECK 2ND BYTE OF FILENAME. IF IT..
	LDAX D		;..IS A ":", THEN DRIVE WAS SPECIFIED.
	DCX D
	CPI ':'
	JNZ DEFDR	;ELSE ZERO FOR DEFAULT DRIVE ('INIT' PUT ZERO)
	LDAX D
	ANI 5FH
	SUI 40H		;CALCULATE DRIVE (A=1, B=2,...)..
	MOV M,A		;..AND PLACE IT IN FCB.
	INX D		;ADDRESS FIRST BYTE OF..
	INX D		;..IN CMD LINE,..
DEFDR	INX H		;..AND NAME FIELD IN FCB.
	RET

TRANS	LDAX D		;TRANSFER FROM CMD LINE TO FCB..
	INX D		;..UP TO NUMBER OF CHARS SPECIFIED..
	CPI 0DH		;..BY C-REG. KEEP SCANNING FIELD..
	RZ		;..WITHOUT TRANSFER UNTIL A DELIMITING..
	CPI '.'		;..FIELD CHAR SUCH AS '.', BLANK, OR..
	RZ		;..C/R (FOR END OF CMD LINE).
	CPI 20H
	RZ
	DCR C
	JM TRANS	;ONCE C-REG IS LESS THAN ZERO, KEEP READING..
	MOV M,A		;..CMD LINE BUT DO NOT TRANSFER TO FCB.
	INX H
	JMP TRANS

SCAN	MVI B,8		;SCAN FILE NAME ADDRESSED BY HL.
TSTNAM	MOV A,M
	CPI '*'		;IF '*' FOUND, FILL IN REST OF FIELD..
	JZ FILL1	;..WITH '?' FOR AMBIGUOUS NAME.
	INX H
	DCR B
	JNZ TSTNAM
	JMP TSTTYP
FILL1	CALL FILL

TSTTYP	MVI B,3		;SCAN AND FILL TYPE FIELD FOR NAME..
TSTTYPL	MOV A,M		;..SPECIFIED ABOVE.
	CPI '*'
	JZ FILL2
	INX H
	DCR B
	RZ
	JMP TSTTYPL
FILL2	CALL FILL
	RET

FILL	MVI M,'?'	;ROUTINE TRANSFERS '?'.
	INX H
	DCR B
	JNZ FILL
	RET

	ENDM

INLNCOMP	MACRO		;NO PARAMETERS USED

;IN-LINE COMPARE. COMPARES STRING ADDRESSED BY DE-REG TO STRING
;AFTER CALL (ENDS WITH ZERO). RETURN WITH CARRY SET MEANS STRINGS
;NOT THE SAME. ALL REGISTERS EXCEPT A-REG ARE UNAFFECTED.

	LOCAL ILCOMPL, SAME, NOTSAME, NSLP

	XTHL		;POINT HL TO 1ST CHAR.
	PUSH D
ILCOMPL	MOV A,M		;HL POINTS TO IN-LINE STRING.
	ORA A		;END OF STRING IF ZERO.
	JZ SAME
	LDAX D
	CMP M
	JNZ NOTSAME
	INX H
	INX D
	JMP ILCOMPL
NOTSAME	MVI A,0		;IF NOT SAME, FINISH THRU..
NSLP	INX H		;..STRING SO RETURN WILL..
	CMP M		;..GO TO INSTRUCTION AFTER..
	JNZ NSLP	;..STRING AND NOT REMAINDER OF STRING.
	STC
SAME	POP D
	INX H		;AVOIDS A NOP INSTRUCTION..
	XTHL		;..WHEN RETURNING.
	RET

	ENDM

MFACCESS	MACRO	;NO PARAMETERS USED

	LOCAL MOVE, CPM, MFNAME, MFN01, MFN02, MFFIX1, MFREQ
	LOCAL MFCUR, MOVER, SRCHF, SRCHN, STDMA, BDOS, FCB, FCBEXT
	LOCAL FCBRNO

	;MFFLG1 IS NOT SET LOCAL BECAUSE IT MUST BE RESET
	;IN MAIN MODEM PROGRAM ON AN ABORT

;
;	MUST BE ASSEMBLED BY "MAC"
;
;MULTI-FILE ACCESS SUBROUTINE.  ALLOWS PROCESSING
;OF MULTIPLE FILES (I.E. *.ASM) FROM DISK.  THIS
;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH
;TIME IT IS CALLED.  THIS COMMAND WOULD BE USED
;IN SUCH PROGRAMS AS MODEM TRANSFER, TAPE SAVE,
;ETC IN WHICH YOU WANT TO PROCESS SINGLE OR
;MULTIPLE FILES.
;
;THE FCB WILL BE SET UP WITH THE NEXT NAME, READY TO
;DO NORMAL PROCESSING (OPEN, READ, ETC.) WHEN ROUTINE IS CALLED.
;
;CARRY IS SET IF NO MORE NAMES CAN BE FOUND
;
;DEFINE DATA MOVE MACRO
;
MOVE	MACRO	?F,?T,?L,?I
	IF	NOT NUL ?F
	LXI	H,?F
	ENDIF
	IF	NOT NUL ?T
	LXI	D,?T
	ENDIF
	IF	NOT NUL ?L
	LXI	B,?L
	ENDIF
	IF	NOT NUL ?I
	LOCAL	?B,?Z
	CALL	?Z
?B	DB	?I
?Z	POP	H	;GET TO
	LXI	B,?Z-?B
	ENDIF
	CALL	MOVER
MF	SET	-1	;;SHOW EXPANSION
	ENDM
;
;DEFINE CP/M MACRO - CPM FNC,PARM
;
CPM	MACRO	?F,?P
	PUSH	B
	PUSH	D
	PUSH	H
	IF	NOT NUL ?F
	MVI	C,?F
	ENDIF
	IF	NOT NUL ?P
	LXI	D,?P
	ENDIF
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	ENDM
;
;------------------------------------------------
;
;	MULTI-FILE ACCESS SUBROUTINE
;
;THE ROUTINE IS COMMENTED IN PSEUDO CODE,
;EACH PSEUDO CODE STATEMENT IS IN <<...>>
;
MFNAME:
;<<INIT DMA ADDR, FCB>>
 CPM STDMA,80H
 XRA A ! STA FCBEXT
;<<IF FIRST TIME>>
 LDA MFFLG1 ! ORA A ! JNZ MFN01
;  <<TURN OFF 1ST TIME SW>>
 MVI A,1 ! STA MFFLG1
;  <<SAVE THE REQUESTED NAME>>
 MOVE FCB,MFREQ,12 ;SAVE ORIG REQ
 LDA FCB ! STA MFCUR ;SAVE DISK IN CURR FCB
;  <<SRCHF REQ NAME>>
 MOVE MFREQ,FCB,12
 CPM SRCHF,FCB
;<<ELSE>>
 JMP MFN02
MFN01:
;  <<SRCHF CURR NAME>>
 MOVE MFCUR,FCB,12
 CPM SRCHF,FCB
;  <<SRCHN REQ NAME>>
 MOVE MFREQ,FCB,12
 CPM SRCHN,FCB
;<<ENDIF>>
MFN02:
;<<RETURN CARRY IF NOT FOUND>>
 INR A ! STC ! JNZ MFFIX1 ! STA MFFLG1 ! RET		;FIX BY M.Z.
MFFIX1:
;<<MOVE NAME FOUND TO CURR>>
 DCR A ! ANI 3 ! ADD A
 ADD A ! ADD A ! ADD A ! ADD A
 ADI 81H ! MOV L,A ! MVI H,0
 PUSH H ;SAVE NAME POINTER
 MOVE ,MFCUR+1,11
;<<MOVE NAME FOUND TO FCB>>
 POP H ! MOVE ,FCB+1,11
;<<SETUP FCB>>
 XRA A ! STA FCBEXT ! STA FCBRNO			;FIX BY M.Z.
;<<RETURN>>
 RET
;
;MULTI-FILE ACCESS WORK AREA
;
MFFLG1	DB	0	;1ST TIME SW
MFREQ	DS	12	;REQ NAME
MFCUR	DS	12	;CURR NAME
;------------------------------------------------
;
;MOVE SUBROUTINE
;
MOVER	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVER
	RET
;
;EQUATES USED BY MULTI-ACCESS SUBROUTINE
;
SRCHF	EQU	17
SRCHN	EQU	18
STDMA	EQU	26				;FIX BY M.Z.
BDOS	EQU	5
FCB	EQU	5CH 
FCBEXT	EQU	FCB+12
FCBRNO	EQU	FCB+32
	ENDM

DIRLIST	MACRO		;NO PARAMETERS USED

	LOCAL DIRLP,PRTNAME,NOFILE,DIRDONE,QSTMARK,QSTLP,PRNTNAME,NEXTSR
	LOCAL MOVENAME,GETADD,DRIVE,CALCDR,SRCHFCB,NAMECT,PRNTHD,DRNAME

	LXI D,CMDBUF	;PUT COMMAND LINE IN FCB
	LXI H,5CH
	CALL CPMLINE
	LXI H,SRCHFCB
	CALL INITFCBS
	LDA 6CH		;GET DRIVE #
	STA SRCHFCB
	LDA 6DH
	CPI 20H		;IF BLANK GET ALL NAMES
	PUSH PSW
	CZ QSTMARK
	POP PSW
	CNZ MOVENAME	;ELSE MOVE NAME INTO FCB
	CALL DRIVE
	LXI D,80H
	MVI C,STDMA
	CALL BDOS
	XRA A
	STA NAMECT	;CR AFTER 4 NAMES
	LXI D,SRCHFCB
	MVI C,SRCHF	;DO FIRST SEARCH
	CALL BDOS
	CPI 0FFH
	JZ NOFILE

DIRLP	CALL GETADD
	LXI D,15	;OFFSET FOR RECORD COUNT
	DAD D
	MOV A,M
	ORA A
	JZ NEXTSR	;NO LIST IF FILE IS ZERO LENGTH
	LXI D,-5
	DAD D		;POINT TO $SYS ATTRIB BYTE
	MOV A,M
	ANI 80H
	JNZ NEXTSR	;NO LIST IF $SYS FILE
	LXI D,-10
	DAD D		;POINT TO BEGINNING OF NAME
	INX H		;POINT TO FIRST LETTER
	LXI D,PRNTNAME
	MVI B,8
	CALL MOVE
	INX D
	MVI B,3
	CALL MOVE
	CALL ILPRT
PRNTNAME
	DB '        ',' ','   ',  ' | ', 0   ;8,1,3 SPACES
	LDA NAMECT
	INR A
	STA NAMECT
	ANI 03H
	ORA A
	CZ CRLF
NEXTSR	LXI D,SRCHFCB
	MVI C,SRCHN	;DO NEXT SEARCH
	CALL BDOS
	CPI 0FFH
	JZ DIRDONE
	JMP DIRLP
NOFILE	CALL ILPRT
	DB 'NOT FOUND',0
DIRDONE	CALL CRLF
	RET

QSTMARK	MVI A,'?'	;IF BLANK IN FCB, PUT IN 11 ?'s
	MVI B,11
	LXI H,SRCHFCB+1
QSTLP	MOV M,A
	INX H
	DCR B
	JNZ QSTLP
	RET

MOVENAME
	LXI H,6DH
	LXI D,SRCHFCB+1
	MVI B,11
	CALL MOVE		;MOVE IN CP/M PROGRAM
	RET

GETADD	ANI 03H			;GET MOD4 FOR CP/M 1.4
	ADD A ! ADD A ! ADD A	;ADD 32
	ADD A ! ADD A
	MOV E,A
	MVI D,0
	LXI H,80H		;ADD DMA OFFSET
	DAD D
	RET

DRIVE	LDA SRCHFCB		;IF NO DRIVE, CAL
	ORA A			;LOGGED IN DRIVE
	JZ CALCDR
	ADI 40H
	JMP PRNTHD
CALCDR	MVI C,25
	CALL BDOS
	ADI 41H
PRNTHD	STA DRNAME
	CALL ILPRT
	DB CR,LF,'DRIVE '
DRNAME	DB ' ',CR,LF,0
	RET

SRCHFCB	DS 33
NAMECT	DS 1

	ENDM
                                                      