*
*********************
*
*
*            MOVE MEMORY ROUTINES
*
*    DE HAS SOU ADDRESS, HL HAS DEST ADDRESS
*       CALL MOVEF
*       MOVE COUNT
*       RETURN
*
*
MOVEF XTHL .  GET RETURN ADDRESS
 MOV C,M  IT POINTED TO THE COUNT
 INX H  MOVE UP RETURN
 XTHL .  PUT IT BACK
 XRA A
 MOV B,A  BC HAS COUNT
 JMP MOVEA
*
*********************
*
*
*    MOVE VARIABLE SIZE BLOCK
*
*  BC HAS COUNT, DE HAS SOURCE, HL HAS DESTINATION
*  CALL MOVEV
*  RETURN
*
MOVV1 LDAX D
 MOV M,A
 INX H  BUMP POINTERS
 INX D
 DCX B
MOVEV MOV A,B
MOVEA ORA C
 JNZ MOVV1
 RET
*
*********************
*
*
*
*                  PREPARE FCB
*
*  UA HAS FCB NUMBER
*  CALL PFCB
*  RETURN FCB   FRADD SET
*  ABORT IF ILLEGAL FCB NUMBER
*
*
PFCB LDA NFCB  GET NUMBER OF FCB'S
 MOV B,A
 LDA UA  GET FILE NUMBER DESIRED
 CMP B
 JNC PFC90  ERROR, TOO BIG
*
 LHLD FCBASE  BOTTOM OF FCB'S
 LXI D,LNFCB  LENGTH OF EACH ONE
 ORA A
 JZ PFC6  FILE "0" NO ADDING NEEDED
*
PFC5 DAD D  MOVE TO NEXT FCB
 DCR A
 JNZ PFC5
*
*
*   SPECIAL ENTRY POINT FOR CLOSE ALL OPERATION
*
*      ENTER WITH HL--> FCB
*
PFC6 SHLD FRADD  SAVE THE FCB ADDRESS
 XCHG
 LXI H,FCBORG  MAKE A COPY TO FCBORG
 CALL MOVEF  MOVE IT
 DB LNFCB
*
*  CHECK IF UNOCCUPIED
*
 LHLD FID
 MOV A,H
 ORA L
 RNZ .  NON ZERO ID, OK
*
PFC90 CALL ERRL1  ERROR
 DB PER1
*
*********************
*
*
*    IF BUFFER IS DYNAMIC RELEASE IT
*
*  CURRENT FCB IS SET
*  CALL RBUF
*  RETURN
*
RBUF LHLD FBUFA
 INX H
 MOV A,H
 ORA L
 RNZ .  FILE IS NOT UNBUFFERED
*
*  RELEASE BUFFER
*
 CALL WDBUF  WRITE DIRTY BUFFER
 LHLD FBLKS
 XCHG .  DE HAS SIZE
 LHLD TBUFA  HL HAS ADDRESS
 CALL DLBUF  DEALLOCATE
 LXI H,0
 SHLD TBUFA  ZERO BUFFER POINTER
 RET
*
*********************
*
*
*        NAMIN, PROCESS IN A NAME
*
*    HL POINTS TO NAME
*    CALL NAMIN
*
*    NAME IS ASSEMBLED INTO DEBUF
*    FUNIT IS SET
*
*  FIRST ZERO OUT NMLEN BYTES
*
NAMIN LXI D,DEBUF
 MVI B,NMLEN
 XRA A
*
NAM05 STAX D
 INX D
 DCR B
 JNZ NAM05
 LXI D,DEBUF  PUT IT HERE
 MVI B,NMLEN+1  MAXCOUNT+1
*
*
*  LOOP HERE WITH:  DE--> NEXT CHARACTER POSITION
*                   B =   NUMBER OF CHARACTERS REMAINING
*                   HL--> NEXT INPUT CHARACTER
*
NAM10 MOV A,M  PICKUP A CHAR
 CALL NAMTST
 JZ ICIN  ERROR!!
*
*  FALL THROUGH WITH LEGAL CHAR IN 'A'
*
NAM20 STAX D
 INX H
 INX D
 DCR B
 JNZ NAM10
*
*  ERROR--TOO MANY CHARACTERS
*
 CALL ERRL1
 DB ERNTL  NAME TOO LONG
*
*
*  ZERO BYTE FOUND (NAMTST COMES HERE)
*
NAM30 POP B  GET RID OF RET
 LDA DUNIT  USE DEFAULT UNIT
NAM31 STA FUNIT  AS FILE UNIT
 LDA DEBUF  CHECK FOR NULL NAME
 ORA A
 RNZ .  IF OK
*
ICIN CALL ERRL1
 DB ICE0  ILLEGAL NAME
*
*
*  FOUND UNIT, PICK IT UP
*
NAM40 POP B
 INX H
 MOV A,M  PICKUP CHAR
 ANI 127
 SBI '0'  SUBTRACT ZERO CHR
 JC ICIU  BAD CHAR
 LXI H,MAXUN  CHECK RANGE OF UNIT NUMBER
 CMP M
 JC NAM31  OK, SELECT IT
*
ICIU CALL ERRL1
 DB ICE1  UNIT ERROR
*
*********************
*
*
*   TEST A NAME CHARACTER IN "A"
*
*   RETURN IF NONSPECIAL LEGAL CHARACTER
*   ERROR  IF ILLEGAL CHARACTER
*
*   GO TO NAM30 OR NAM40 IF TERMINATOR FOUND
*   (RETURN DISPOSED OF)
*
NAMTST ANI 127  MASK DOWN
 JZ NAM30  END OF NAME
 CPI '/'  SLASH?
 JZ NAM40  SELECT UNIT
 CALL DLTST  CHECK FOR BAD CHARS
 RZ .  IF SO
*
 CPI '#'  THE OTHER ONES
 RZ .  BAD
 CPI ' '+1 SPACE
 JC ICIN  CONTROL CHAR OR SPACE
 CPI 127  NOT .EQ. OR .GT.
 RET .  LEGAL CHAR
*
 PAGE
*
*
*********************
*
*
*
*               SEARCH DIRECTORY
*
*
*   HL POINTS TO NAME, CURRENT DIREC SET
*
*      CALL SDIR
*      RETURN = NOT FOUND
*      RETURN = FOUND, DBUF POINTS TO ENTRY WITH ROOM OR
*               IS ZERO IF THE DIRECTORY IS FULL.
*
SDIR CALL NAMIN  PROCESS NAME
 XRA A
 STA DRID  SET ID TO ZERO
 STA DRID+1
*
*  ALTERNATE ENTRY FROM SDIRX
*  COME HERE WITH A=0,DRID EQU FILE ID
*
SDI02 STA DFC  INITIALIZE
 STA DFC+1  FREE POINTER
*
*  READ FIRST SECTOR
*
 LXI D,DDSC
 LXI H,TDAD
 CALL MOVEF  SET TRANSFER DESCRIPTOR
 DB TBUF-TDAD+2
 LDA FUNIT
 STA TUNIT  DISK UNIT
*  READ
SDI07 CALL RDSK
*
*  SEE ABOUT FREE STUFF
*
 LHLD DFC
 MOV A,L
 ORA H
 JNZ SDI20  ALREADY FOUND ONE
 LDA DINE
 CPI DREMS
 JNC SDI20  SECTOR IS FULL
 LHLD TDAD
 SHLD DFC  SAVE AVAILABLE SECTOR
*
*  SET UP DIRECTORY SECTOR SEARCH
*
SDI20 LXI H,DRFDS  FIRST ENTRY ADDRESS
 SHLD DBUF  SAVE POINTER
 LDA DINE
 STA DCNT  SAVE COUNT
 ORA A
 JZ SDI70  SECTOR IS EMPTY, MOVE TO NEXT
*
*  LOOP AND TEST ENTRIES
*
SDI30 LHLD DRID
 MOV A,L
 ORA H
 JNZ SDI50  ITS A SEARCH BY ID
*
*  TEST NAME
*
 LXI D,DEBUF  USER NAME
 LHLD DBUF  NAME IN SECTOR
*
*  COMPARE STRINGS
*
 MVI B,NMLEN
SDI40 LDAX D
 CMP M
 JZ SDI44  MATHC ON THIS CHARACTER
*
*  TRY TO MATCH UPPER/LOWER CASE CHARACTERS
*
 CPI 97  ="a"
 JC SDI42  DEBUF CHARACTER NOT LOWER CASE
 SBI 32  DEBUF CHAR WAS LC, UPSHIFT AND TRY
 JMP SDI43  TO MATCH AGAIN
*
* DEBUF CHAR NOT LC,  TRY TO UPSHIFT DIREC CHAR
*
SDI42 MOV A,M
 CPI 97  ="a"
 JC SDI60  DIREC CHAR NOT LC, NO MATCH
 LDAX D  GET DEBUG CHAR
 ADI 32  DOWNSHIFT DEBUG CHAR TO TRY MATCH
*
* TRY ALTERNATE MATCH
*
SDI43 CMP M
 JNZ SDI60  NO, SECOND MATCH ATTEMPT FAILED
*
SDI44 INX D  MATCH
 INX H
 DCR B  MOVE TO NEXT CHARACTER
 JNZ SDI40
*
*  MATCH
*
SDI45 LHLD DBUF  MOVE ENTRY INTO
 XCHG
 LXI H,DEBUF  DEBUF
 CALL MOVEF
 DB DRESZ
 JMP RP2  RETURN TO CALL PLUS 2
*
*
*  MOVE TO NEXT ENTRY
*
SDI60 LDA DCNT
 DCR A  COUNT DOWN
 JZ SDI70  SECTOR EMPTY
 STA DCNT
 LHLD DBUF
 LXI D,DRESZ  MOVE POINTER
 DAD D
 SHLD DBUF
 JMP SDI30
*
*
*   MOVE TO NEXT SECTOR
*
SDI70 LHLD IHFOR  FORE POINTER
 MOV A,H
 ORA A
 RM .  EOF, FAIL
 SHLD TDAD  SET NEXT SECTOR
 JMP SDI07
*
*
*  CHECK FILE ID, NOT NAME
*
SDI50 LHLD DBUF
 LXI D,DEFID-DEBUF
 DAD D  HL POINT TO ID
 LDA DRID
 CMP M
 JNZ SDI60  NOT SAME
 INX H
 LDA DRID+1
 CMP M
 JNZ SDI60  NOPE
 JMP SDI45  YES, MATCH
*
*********************
*
*
*             SEARCH DIRECTORY BY ID
*
*    SAME AS SDIR BUT HL HAVE ID
*    ENTER AT SDIRY WITH A = UNIT#, ALSO
*
*   THE FILE MUST EXIST.  THE DIRECTORY ON WHICH THE
*   FILE EXISTS IS SEARCHED.
*
SDIRY STA FUNIT  SPECIAL ENTRY FOR "OPEN?"
SDIRX SHLD DRID  SAVE ID
 XRA A  SET A TO ZERO
 CALL SDI02  GO SEARCH
 CALL CI98  FILE MUST EXIST, OR ELSE!
 RET
*
*********************
*
*
*    DIRECTORY FILE DESCRIPTOR
*
DDSC DB DIRDS  SECTOR
 DB DIRDT  TRACK
DDSC2 DW SECTSZ  BYTE COUNT
 DW IDDIR  FILE ID
 DW DIBUF  BUFFER
*
*********************
*
*
*     MAKE ENTRY IN DIRECTORY
*
*  DEBUF HAS ENTRY, DFC IS SET
*
EDIR LHLD DFC
 MOV A,L
 ORA H
 CZ CI98  BETTER NOT BE FULL!
*
*  READ SECTOR WITH FREE ENTRY
*
EDI10 SHLD TDAD  SAVE DISK ADDRESS
 LXI D,DDSC2
 LXI H,TBCNT
 CALL MOVEF  MOVE IN DIRECTORY DESCRIPTOR
 DB TBUF-TBCNT+2
 LDA FUNIT
 STA TUNIT  UNIT
 CALL RDSK  READ SECTOR
*
*  MOVE IN ENTRY
*
 LXI D,DIBUF
 XRA A
 MOV H,A
 LDA DIND
 MOV L,A  HL = NEXT DISPLACEMENT
 DAD D  HL = DESTINATION
 LXI D,DEBUF  DE = ENTRY BUFFER
 CALL MOVEF
 DB DRESZ
*
*  UPDATE HEADER
*
 LDA DINE
 INR A
 STA DINE  NUMBER OF ENTRIES
 LDA DIND
 ADI DRESZ
 STA DIND  NEXT ENTRY DISPLACEMENT
 CALL WDSK  RE WRITE THE ENTRY
 RET .  THATS ALL
*
*********************
*
*
*      REMOVE DIRECTORY ENTRY
*
*  DIBUF HAS SECTOR
*  DBUF  POINTS TO ENTRY
*  ALWAYS NORMAL RETURN
*
RDIR LDA DINE
 DCR A  UPDATE COUNT
 STA DINE
 JZ RDI60  IT IS NOW ZERO, NOTHING TO MOVE
*
*    CALCULATE NUMBER OF WORDS TO MOVE
*
*  HERE I ASSUME (DBUF MOD 256)-(DIBUF MOD 256)
*  = (DBUF-DIBUF) MOD 256 WHICH IS BEING PROVEN.
*
 LXI D,DIBUF
 LHLD DBUF
 MOV A,L
 SUB E  = WORDS BEFORE ENTRY
 MOV B,A
 LDA DIND  DISPLACEMENT TO NEXT
 SUB B  = WORDS AFTER ENTRY + WORDS IN ENTRY
 SUI DRESZ  = WORDS AFTER ENTRY
 JZ RDI60  ZERO, NO MOVING INVOLVED
 MOV C,A
 XRA A  = O
 MOV B,A  BC HAS COUNT
 LHLD DBUF
 LXI D,DRESZ
 PUSH H  SAVE DBUF FOR DESTINATION
 DAD D  = SOURCE ADDRESS (DBUF+DRESZ)
 XCHG .  PUT IN DE
 POP H  = DESTINATION ADDRESS (DBUF)
 CALL MOVEV  RECALL THAT BC HAS COUNT
*
RDI60 LDA DIND
 SUI DRESZ  UPDATE NEXT ENTRY DISPLACEMENT
 STA DIND
 CALL WDSK  TDAD STILL IS SET, REWRITE
 RET
*
*********************
*
*
*        GET FILE ID
*
*  CURRENT LOGICAL UNIT DESCRIPTOR IS SET UP
*  CALL GFID
*  RET WITH ID IN DE
*  ABORT IF NO IDS ARE AVAILABLE
*
*  SET UP READ
*
GFID LXI D,NIDD
 LXI H,TDAD
 CALL MOVEF  SET TRANSFER DESCRIPTOR
 DB TBUF-TDAD+2
 LDA FUNIT
 STA TUNIT  UNIT.
 CALL RDSK  READ IT
*
 LHLD IDBUF
 PUSH H  SAVE ID
 INX H  INCREMENT
 MOV A,H
 ORA L
 JZ NOIDS  NO IDS LEFT, SERIOUS
 SHLD IDBUF  OK, REWRITE
 CALL WDSK
 POP D  PUT ID INTO DE
 RET
*
*
NOIDS POP D  GET RID OF IT
 CALL ERRL0
 DB IER0  NO IDS LEFT
*
*********************
*
*
*    FSM DESCRIPTOR
*
NIDD DB DANIS  SECTOR
 DB DANIT  TRACK
 DW NIDBC  BYTE COUNT
 DW IDNID  FILE ID
 DW IDBUF  BUFFER
*
*********************
*
*
*    WRITE BUFFER TO DEVICE IF DIRTY
*
WDBUF LDA FFLAG
 ORA A  TEST DIRTY FLAG
 RZ .  NOT DIRTY
*
 LHLD FBDL  THE LAST BYTE IN THE BUFFER
 XCHG
 LHLD TBUFA  SET HL=START ADDRESS, DE=LAST ADDRESS
 CALL DVBR  WRITE BLOCK
 DB DTWB
 JMP SEOF  EOF, ERROR
 JMP WDB50
*
*********************
*
*
*          READ NEXT BUFFER LOAD FROM DEVICE
*
* CLEAN BUFFERS, READ BLOCK, THEN SET NBD=0,
* AND BDL=INCOMING BLOCK SIZE
* COME WITH HL=BUFFER SIZE
*
RDNB PUSH H
 CALL WDBUF  CLEAN IF DIRTY
 POP D
 LHLD TBUFA
 CALL DVBR  READ NEXT
 DB DTRNB
 RET .  EOF ENCOUNTERED
 NOP
 NOP
 SHLD FBDL  SET BDL
 LXI H,0
 SHLD FNBD  NBD=0
 JMP RP2  RETURN CALL +2
*
*********************
*
*
*     WRITE CURRENT BUFFER AND LOAD NEXT
*
*  CALL WITH SIZE IN HL
*  SET NBD=0, BDL FROM DRIVER, FFLAG=0
*
WDBR XCHG
 LHLD TBUFA
 CALL DVBR  WRITE
 DB DTWBR
 JMP SEOF  EOF, ERROR
*
WDB45 SHLD FBDL  SET BDL
 LXI H,0
 SHLD FNBD  NBD=0
*
WDB50 XRA A
 STA FFLAG  FFLAG=0
 RET .  RETURN
*
*********************
*
*
*              DEVICE DRIVER BRANCH
*
*  CALL WITH CALL+1=OPERATION
*  PASS DE, HL, AND A TO THE DRIVER
*
DVBR XTHL
 MOV C,M  PICKUP DISPLACEMENT
 INX H  MOVE PAST IT
 MVI B,0  BC=DISPLACEMENT
 XTHL .  SAVE UPDATED RETURN
 PUSH H
 LHLD FDRIV
 DAD B  HL->DISPATCH ADDRESS
 MOV B,A
 MOV A,M  PICKUP FIRST PART
 INX H
 MOV H,M  THEN SECOND
 MOV L,A  HL=DISPATCH ADDRESS
 ORA H
 JZ IDAC  NO ZERO OPERATION.. ERROR
 MOV A,B
 XTHL .  RESTORE HL,
 RET .  THEN GO INTO DRIVER.
*
*********************
*
*
*            DISK DRIVER READ LAST BLOCK
*
DDRLB LHLD FBACK  GET BACK POINTER
 MOV A,H  TEST FOR BOF
 ORA A
 RM .  YES, WE'RE ALL THE WAY BACK
 SHLD FCURSC  SET AS CURRENT SECTOR AND FALL THROUGH
*
*
*
*          DISK DRIVER READ BLOCK
*
DDRBL CALL RBLK
RX2 XTHL .  RETURN CALL+2, BUT
 INX H  LEAVE
 INX H  HL
 INX H  ALONE.
 XTHL
 RET
*
*
