;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