;
;               FMAP.ASM
;           (revised 6/12/80)
;
;ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;SORTED DIRECTORY MAP PROGRAM
;WITH OPTION OF WRITING FILE OF NAMES
;
;FMAP FN.FT OR JUST MAP
;FMAP FN.FT F   TO WRITE A FILE
;ALLOWS '*' OR '?' TYPE SPECIFICATIONS
;
;10/30/79 MODIFIED TO ALLOW FOR 128 DIRECTORY ENTRIES
;         (KEITH PETERSEN, W8SDZ).
;12/29/79 CORRECTED ERROR IN CONSTAT TEST
;         FOR ABORTING PRINT.  (KBP)
;06/12/80 ADD ANI 7FH TO REMOVE FILE ATTRIBUTES
;         TO MAKE COMPATIBLE WITH CPM-2. (KBP)
;
FCB     EQU     5CH     ;SYSTEM FCB
;
       ORG     100H
       JMP     START   ;SKIP PROGRAM ID
       DB      '(FMAP 6/12/80)'
;SAVE THE STACK
START   LXI     H,0
       DAD     SP      ;H=STACK
       SHLD    STACK   ;SAVE IT
       LXI     SP,STACK ;GET NEW STACK
;SAVE FILE WRITE REQUEST CHAR
       LDA     FCB+17
       STA     FILESW
;NO FCB SPECIFIED?
       LXI     H,FCB+1
       MOV     A,M
       CPI     ' '
       JNZ     GOTFCB
;NO FCB - MAKE FCB ALL '?'
       MVI     B,11    ;FN+FT COUNT
QLOOP   MVI     M,'?'   ;STORE '?' IN FCB
       INX     H
       DCR     B
       JNZ     QLOOP
;LOOK UP THE FCB IN THE DIRECTORY
GOTFCB  MVI     C,FSRCHF ;GET 'SEARCH FIRST' FNC
       LXI     D,FCB
       CALL    BDOS    ;READ FIRST
       INR     A       ;WERE THERE ANY?
       STA     TEMP    ;SAVE
       JNZ     PRTTL   ;GOT SOME - PRT TITLE, CONT
       LXI     D,NONMSG
       CALL    WRCON
       JMP     EXIT
;
NONMSG  DB      '++NOT FOUND$'
;
;PRINT TITLE
PRTTL   LXI     D,TTL
       CALL    WRCON
       CALL    CR
       LDA     TEMP    ;RELOAD EXTENT
       JMP     SOME
;
TTL     DB      'FILENAME TYP RC -----GROUPS------$'
;
;READ MORE DIRECTORY ENTRIES
MOREDIR MVI     C,FSRCHN ;SEARCH NEXT
       LXI     D,FCB
       CALL    BDOS    ;READ DIR ENTRY
       INR     A       ;CHECK FOR END (0FFH)
       JZ      SPRINT  ;NO MORE - SORT & PRINT
;POINT TO DIRECTORY ENTRY
SOME    DCR     A       ;UNDO PREV 'INR A'
       ANI     3       ;MAKE MODULUS 4
       ADD     A       ;MULTIPLY...
       ADD     A       ;..BY 32 BECAUSE
       ADD     A       ;..EACH DIRECTORY
       ADD     A       ;..ENTRY IS 32
       ADD     A       ;..BYTES LONG
       LXI     H,81H   ;POINT TO BUFFER
                       ;(SKIP TO FN/FT)
       ADD     L       ;POINT TO ENTRY
       MOV     L,A     ;SAVE (CAN'T CARRY TO H)
;MOVE ENTRY TO TABLE
       XCHG            ;ENTRY TO DE
       LHLD    NEXTT   ;NEXT TABLE ENTRY TO HL
       MVI     B,11    ;NAME ENTRY LENGTH
TMOVE   LDAX    D       ;GET ENTRY CHAR
       ANI     7FH     ;REMOVE ATTRIBUTES
       MOV     M,A     ;STORE IN TABLE
       INX     D
       INX     H
       DCR     B       ;MORE?
       JNZ     TMOVE
       MVI     B,20    ;REST OF ENTRY LENGTH
;
TMOVE2  LDAX    D       ;GET ENTRY CHAR
       MOV     M,A     ;STORE IN TABLE
       INX     D
       INX     H
       DCR     B       ;MORE?
       JNZ     TMOVE2
       SHLD    NEXTT   ;SAVE UPDATED TABLE ADDR
       LDA     COUNT   ;GET PREV COUNT
       INR     A
       STA     COUNT
       JMP     MOREDIR
;
;SORT AND PRINT
SPRINT  LDA     COUNT   ;INIT THE ORDER TABLE
       LXI     H,ORDER
       LXI     D,TABLE
       LXI     B,31    ;ENTRY LENGTH
;
BLDORD  MOV     M,E     ;SAVE LO ORD ADDR
       INX     H
       MOV     M,D     ;SAVE HI ORD ADDR
       INX     H
       XCHG            ;TABLE ADDR TO HL
       DAD     B       ;POINT TO NEXT ENTRY
       XCHG
       DCR     A       ;MORE?
       JNZ     BLDORD  ;..YES
       LDA     COUNT   ;GET COUNT
       STA     SCOUNT  ;SAVE AS # TO SORT
       DCR     A       ;ONLY 1 ENTRY?
       JZ      DONE    ;..YES, SO SKIP SORT
;
SORT    XRA     A       ;GET A ZERO
       STA     SWITCH  ;SHOW NONE SWITCHED
       LDA     SCOUNT  ;GET COUNT
       DCR     A       ;USE 1 LESS
       STA     TEMP    ;SAVE # TO COMPARE
       STA     SCOUNT  ;SAVE HIGHEST ENTRY
       JZ      DONE    ;EXIT IF NO MORE
       LXI     H,ORDER ;POINT TO ORDER TABLE
;
SORTLP  CALL    COMPR   ;COMPARE 2 ENTRIES
       CM      SWAP    ;SWAP IF NOT IN ORDER
       INX     H       ;BUMP ORDER
       INX     H       ;..TABLE POINTER
       LDA     TEMP    ;GET COUNT
       DCR     A
       STA     TEMP
       JNZ     SORTLP  ;CONTINUE
;
;ONE PASS OF SORT DONE
       LDA     SWITCH  ;ANY SWAPS DONE?
       ORA     A
       JNZ     SORT
;
;SORT IS ALL DONE - PRINT ENTRIES
DONE    LXI     H,ORDER
       SHLD    NEXTT
;IF WRITING A FILE, OPEN THE FILE
       LDA     FILESW
       CPI     'F'
       JNZ     ENTRY
       LXI     D,MYFCB
       MVI     C,ERASE
       CALL    BDOS
       LXI     D,MYFCB
       MVI     C,FMAKE ;MAKE THE FILE
       CALL    BDOS
       INR     A
       JNZ     ENTRY
;MAKE ERROR
       CALL    ERXIT
       DB      '++FILE MAKE ERROR$'
;
;PRINT AN ENTRY
ENTRY   MVI     C,CONST ;CK STATUS OF KBD
       CALL    BDOS    ;ANY KEY PRESSED?
       ORA     A
       JNZ     ABORT   ;YES, ABORT
       LHLD    NEXTT   ;GET ORDER TABLE POINTER
       MOV     E,M     ;GET LO ADDR
       INX     H
       MOV     D,M     ;GET HI ADDR
       INX     H
       SHLD    NEXTT   ;SAVE UPDATED TABLE POINTER
       XCHG            ;TABLE ENTRY TO HL
       MVI     B,8     ;FILE NAME LENGTH
       CALL    TYPEIT  ;TYPE FILENAME
       CALL    PERIOD  ;SPACE AFTER FN
       MVI     B,3     ;GET THE FILETYPE
       CALL    TYPEIT
       CALL    FILECR
       INX     H       ;SKIP EXTENT
       INX     H       ;SKIP
       INX     H       ;UNUSED
       MOV     A,M     ;GET REC COUNT
       DCR     A       ;FUDGE
       RAR             ;DIVIDE
       RAR             ;..BY 8
       RAR
       ANI     1FH     ;DELETE GARBAGE
       INR     A       ;MAKE RELATIVE TO 1, NOT 0
       MOV     B,A     ;SAVE AS # EXTENTS
       MOV     A,M     ;RELOAD RECORD COUNT
       CALL    XOB     ;PRINT RECORD COUNT
       INX     H       ;SKIP RECORD COUNT
       MVI     C,0     ;FOR EXTENT SKIP CTL
;
EXTLP   MOV     A,M     ;GET EXTENT BYTE
       ORA     A       ;EMPTY?
       JZ      ENDEXT  ;..YES
       CALL    XO      ;..NO, PRINT IT
       INR     C       ;INCR COUNT
       MOV     A,C     ;TIME TO SPACE?
       ANI     3
       CZ      SPACE
       INX     H       ;POINT TO NEXT CHR
       DCR     B       ;MORE IN EXTENT?
       JNZ     EXTLP   ;YES
;
;BUMP TOTAL FILE COUNT
ENDEXT  LDA     NFILE   ;GET # FILES
       INR     A       ;BUMP
       DAA             ;MAKE DECIMAL
       STA     NFILE   ;SAVE IT BACK
       CALL    CR      ;END, TYPE C/R
;SEE IF MORE ENTRIES
       LDA     COUNT
       DCR     A
       STA     COUNT
       JNZ     ENTRY   ;YES, MORE
;ALL DONE - PRINT # FILES
       LDA     NFILE
       CALL    XOB
       LXI     D,NMSG
       CALL    WRCON
;CLOSE FILE IF NECESSARY
       LDA     FILESW
       CPI     'F'
       JNZ     EXIT
       MVI     A,'Z'-40H ;EOF CHAR
       CALL    FILCHR  ;WRITE IT
       CALL    WRSEC   ;WRITE FINAL SECTOR
       LXI     D,MYFCB
       MVI     C,FCLOSE
       CALL    BDOS
       JMP     EXIT
;
NMSG    DB      'FILES$'
;
;HEX OUTPUT W/BLANK
XOB     CALL    XO
       JMP     SPACE
;
;HEX OUTPUT
XO      PUSH    PSW     ;SAVE CHAR
       RAR
       RAR
       RAR
       RAR
       CALL    NIBBL   ;PRINT LEFT NIBBLE
       POP     PSW     ;GET VALUE BACK
NIBBL   ANI     0FH     ;ISOLATE NIBBLE
       CPI     10      ;NUMBER?
       JC      XNUM    ;YES
       ADI     7       ;FUDGE ALPHA HEX
XNUM    ADI     '0'     ;MAKE PRINTABLE
;
;TYPE CHAR IN A
TYPE    PUSH    B
       PUSH    D
       PUSH    H
       MOV     E,A
       MVI     C,WRCHR
       CALL    BDOS
       POP     H
       POP     D
       POP     B
       RET
;
WRCON   MVI     C,PRINT
       JMP     BDOS
;
TYPEIT  MOV     A,M
       CALL    FILCHR  ;TO DISK IF REQ'D
       CALL    TYPE
       INX     H
       DCR     B
       JNZ     TYPEIT
       RET
;
SPACE   MVI     A,' '
       JMP     TYPE
;
CR      MVI     E,13    ;PRINT
       MVI     C,2     ;C/R
       CALL    BDOS
       MVI     E,10    ;LF
       MVI     C,2
       JMP     BDOS
;
;ERROR EXIT
ERXIT   POP     D       ;GET MSG
       MVI     C,PRINT
       JMP     CALLB   ;PRINT MSG, EXIT
;
;ABORT - READ CHAR ENTERED
ABORT   MVI     C,RDCHR
CALLB   CALL    BDOS    ;DELETE THE CHAR
;FALL INTO EXIT
;
;EXIT - ALL DONE , RESTORE STACK
EXIT    LHLD    STACK   ;GET OLD STACK
       SPHL            ;MOVE TO STACK
       RET             ;..AND RETURN
;
;ROUTINES FOR CREATING FILE
;
;WRITE CHAR IN A TO FILE
;(SAVES ALL REGS INCLUDING A)
FILCHR  CPI     ' '
       RZ              ;DON'T WRITE BLANKS
       PUSH    PSW
       LDA     FILESW  ;WRITING A FILE?
       CPI     'F'
       JNZ     NOFILE
       POP     PSW     ;GET CHAR
       PUSH    PSW     ;SAVE IT BACK
       PUSH    H
       LHLD    BUFAD   ;CURRENT BUFFER ADDR
       MOV     M,A
       INX     H
       SHLD    BUFAD
       MOV     A,H     ;SEE IF FULL BUFF
       DCR     A
       CZ      WRSEC   ;YES, WRITE SECTOR
       POP     H
NOFILE  POP     PSW     ;RESTORE CHAR
       RET
;
;WRITE A SECTOR
WRSEC   PUSH    B
       PUSH    D
       LXI     D,MYFCB
       MVI     C,FWRTE
       CALL    BDOS
       ORA     A
       JZ      WROK
       CALL    ERXIT
       DB      '++WRITE ERROR$'
;
WROK    LXI     H,80H   ;START OF BUFF
       SHLD    BUFAD
       POP     D
       POP     B
       RET
;
;TYPE A PERIOD INTO THE FILE
PERIOD  MVI     A,'.'   ;GET PERIOD
       CALL    FILCHR  ;WRITE TO FILE
       JMP     SPACE
;
;WRITE CR/LF INTO FILE
FILECR  MVI     A,13
       CALL    FILCHR
       MVI     A,10
       CALL    FILCHR
       JMP     SPACE
;
;COMPARE ROUTINE FOR SORT
COMPR   PUSH    H       ;SAVE TABLE ADDR
       MOV     E,M     ;LOAD LO
       INX     H
       MOV     D,M     ;LOAD HI
       INX     H
       MOV     C,M
       INX     H
       MOV     B,M
;BC, DE NOW POINT TO ENTRIES TO BE COMPARED
       XCHG
CMPLP   LDAX    B
       CMP     M
       INX     H
       INX     B
       JZ      CMPLP
       POP     H
       RET             ;COND CODE TELLS ALL
;
;SWAP ENTRIES IN THE ORDER TABLE
SWAP    MVI     A,1
       STA     SWITCH  ;SHOW A SWAP WAS MADE
       MOV     C,M
       INX     H
       PUSH    H       ;SAVE TABLE ADDR+1
       MOV     B,M
       INX     H
       MOV     E,M
       MOV     M,C
       INX     H
       MOV     D,M
       MOV     M,B
       POP     H
       MOV     M,D
       DCX     H       ;BACK POINTER TO CORRECT LOC'N
       MOV     M,E
       RET
;
NFILE   DB      0       ;NUMBER OF FILES PRINTED
NEXTT   DW      TABLE   ;NEXT TABLE ENTRY
COUNT   DB      0       ;ENTRY COUNT
SCOUNT  DB      0       ;# TO SORT
SWITCH  DB      0       ;SWAP SWITCH FOR SORT
BUFAD   DW      80H     ;OUTPUT ADDR
MYFCB   DB      0,'NAMES   SUB',0
       DS      19
       DB      0
FILESW  DS      1       ;'F' IF WRITING FILE
TEMP    DS      1       ;SAVE DIR ENTRY
       DS      60      ;STACK AREA
STACK   DS      2       ;SAVE OLD STACK HERE
ORDER   DS      256     ;ORDER TABLE (ROOM FOR 128 NAMES)
TABLE   EQU     $       ;READ ENTRIES IN HERE
;
; BDOS EQUATES
;
RDCHR   EQU     1       ;READ CHAR FROM CONSOLE
WRCHR   EQU     2       ;WRITE CHR TO CONSOLE
PRINT   EQU     9       ;PRINT CONSOLE BUFF
CONST   EQU     11      ;CHECK CONS STAT
FOPEN   EQU     15      ;0FFH=NOT FOUND
FCLOSE  EQU     16      ;   "   "
FSRCHF  EQU     17      ;   "   "
FSRCHN  EQU     18      ;   "   "
ERASE   EQU     19      ;NO RET CODE
FREAD   EQU     20      ;0=OK, 1=EOF
FWRTE   EQU     21      ;0=OK, 1=ERR, 2=?, 255=NO DIR SPC
FMAKE   EQU     22      ;255=BAD
FREN    EQU     23      ;255=BAD
FDMA    EQU     26
BDOS    EQU     5
REBOOT  EQU     0
;
       END     100H