home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
sigm
/
sigmv017.ark
/
XDIR.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
13KB
|
534 lines
TITLE 'XDIR - CP/M DIRECTORY DISPLAY PROGRAM'
; - XDIR -
; BY S J SINGER
;MODIFICATIONS
; MAY 15, 1980 - ADDED SUPPORT FOR DRIVES A-D
; MAY 15, 1980 - CHANGED THE DISPLAY TO 18 LINES
; MAY 15, 1980 - FIXED BUG WITH DIR EXTENTS NOT BEING IN
; ORDER. IF A LARGER EXTENT CAME BEFORE
; EXTENT ZERO, THE PROGRAM WOULD LOOP INFINITELY.
; MAY 24, 1980 - CHANGED SO THAT DIR ENTRIES ARE READ VIA
; BDOS CALLS (011H AND 012H).
; MAY 24, 1980 - CHANGED SO THAT SPACE INFO IS GOTTEN IN
; ACCORDANCE WITH CP/M 2.0 AND ABOVE.
;
; XDIR IS A CPM UTILITY THAT DISPLAYS A DISK DIRECTORY IN A MORE
;READABLE FORM. THE DIRECTORY IS READ FROM THE SPECIFIED DISK, SORTED
;THEN DISPLAYED IN A 3 COLUMN FORMAT. BOTH THE FILE NAMES AND FILE SIZES
;IN 1 K GROUPS ARE DISPLAYED.
; THE PRESENT VERSION OF XDIR HAS CERTAIN MINOR LIMITATIONS WHICH
;MAY BE EASILY REMOVED IF THEY CAUSE PROBLEMS.
;
; 1. ONLY 54 FILES ARE DISPLAYED. THIS LIMIT IS SUFFICIENT FOR
; ALMOST ALL DISKS AND LEAVES ROOM ON THE SCREEN FOR EDITING.
; TO CHANGE THE NO OF LINES DISPLAYED, CHANGE THE LINES VARIABLE
; IN THE DATA ALLOCATION SECTION OF THE PROGRAM. FOR EXAMPLE
; TO DISPLAY A MAXIMUM OF 54 FILES CHANGE LINES TO 18.
;
; OCCASIONALLY THE FILE NAMES WILL BE DISPLAYED WITH THE FORMAT
;SCRAMBLED OR THE SPACE REMAINING ON THE DISK WILL NOT AGREE WITH THAT REPORTED
;BY THE STAT UTILITY. THIS ALMOST ALWAYS MEANS THE DISK DIRECTORY HAS BEEN
;MESSED UP SOMEHOW. USUALLY THE PROBLEM CAN BE CORRECTED BY COPYING ALL THE
;FILES TO ANOTHER DISK USING PIP.
; XDIR WAS ASSEMBLED USING THE NEW CP/M MACRO ASSEMBLER AND USES A LARGE
;NUMBER OF MACROS. THESE ARE CONTAINED IN A LIBRARY CALLED MACRO.LIB WHICH
;IS REQUIRED IF THE PROGRAM IS TO BE REASSEMBLED.
;
;
; COMMAND FORMAT
;
; XDIR DISPLAY DIRECTORY OF LOGGED DISK
; XDIR A DISPLAY DIRECTORY OF DISK A
; XDIR B DISPLAY DIRECTORY OF DISK B
; XDIR C DISPLAY DIRECTORY OF DISK C
; XDIR D DISPLAY DIRECTORY OF DISK D
;
;
; THE PROGRAM STARTS READING THE CP/M DIRECTORY UNTIL AN EOF OCCURS.
;AS IT READS EACH ENTRY, IT MAINTAINS A TABLE OF ALL FILES. THE TABLE CON-
;TAINS ONE ENTRY FOR EACH FILE FROM ITS LARGEST EXTENT. WHEN ALL FILES ARE
;IN THE TABLE, IT SORTS THEM USING QUICKSORT AND AN AUXILIARY ADDRESS TABLE.
;WHEN THE SORT COMPLETES, THE FILE TABLE IS PRINTED IN THE ORDER OF THE AUX
;ADDRESS TABLE AND CONTROL IS GIVEN BACK TO CP/M.
; * * * COMMON EQUATES * * *
LINES EQU 18 ;LINES PER PAGE OF DISPLAY
MAXDIR EQU 128 ;MAXIMUM NUMBER OF DIRECTORY ENTRIES
MACLIB MACRO ;INCLUDE MACRO LIBRARY
PAGE
;************************************************
;* PROGRAM INITIALIZATION *
;************************************************
ORG 100H ;SET PROG START
LXI H,0
DAD SP ;GET OLD STACK POINTER
SHLD OLDSTK ;SAVE IT
LXI SP,NEWSTK ;LOAD NEW STACK POINTER
;
; START OF DIRECTORY ROUTINE READ IN GROUPS 0 AND 1 AND STORE
; DIRECTORY FILE NAMES NOT FLAGGED E5. IF EXTENT NOT ZERO STORE
; OVER PREVIOUS FILE NAME. TABLE OF POINTERS WILL BE BUILT IN PDIR
;
DIR: DISKIO ?DRIVE
STA NEWDRV
LDA 81H
ORA A ;CHECK IF INPUT BUFFER EMPTY
JZ DDD
LDA 82H ;CHECK NEW DRIVE (A-D)
CPI 'A'
JC DSKERR
CPI 'D'+1
JNC DSKERR
SUI 'A' ;MAKE IT RELATIVE TO ZERO.
STA NEWDRV ;SAVE IT.
DDD: PRINT <CR,LF,LF,' DIRECTORY DRIVE - '>
LDA NEWDRV ;LOGGED DISK
ADI 'A'
CHAROUT
PRINT <CR,LF,LF>
CALL FIXB ;RESTORE DRIVE.
; GET THE CURRENT DISK MAX VALUE.
MVI C,01FH ;GET DPB ADR FROM CP/M.
CALL 5
SHLD DPBADR ;SAVE IT.
LXI D,2 ;GET THE BSH.
DAD D
MOV A,M ;SAVE IT.
STA DSKBSH
MOV C,A ; AGAIN.
INX H ;GET THE BLM FOR LATER.
MOV A,M
STA DSKBLM ;SAVE IT.
MOV A,C ;CONVERT BSH TO REL SHIFT.
SUI 3
MOV C,A ;SAVE IT.
INX H ;GET THE DSM.
INX H
MOV E,M
INX H
MOV D,M
INX H
XCHG
INX H ;MAKE IT RELATIVE TO ONE.
DCR C ;SHIFT MAX BY (C) TIMES.
INR C
JZ $+8
DAD H
DCR C
JMP $-7
SHLD MAXSTR ;SAVE VALUE.
; GET DIRECTORY SIZE.
XCHG ;HL = DPBDRM
MOV E,M
INX H
MOV D,M
XCHG
INX H ;MAKE IT RELATIVE TO ONE.
LXI D,32-1 ;ROUND IT TO EVEN # OF K.
DAD D
HALF ;DIVIDE IT BY 32 (# IN 1K).
HALF ;/4
HALF ;/8
HALF ;/16
HALF ;/32
SHLD DIRSIZ ;SAVE IT.
; ADJUST MAX SIZE BY DIRECTORY SIZE.
LHLD MAXSTR
DSUB DIRSIZ
SHLD MAXSTR
DIR2: XRA A
STA COUNT ;COUNT OF DIRECTORY ENTRIES
; FILL PDIR,PDIR+(2*(MAXDIR+1)) ;ZERO DIR PTR TABLE
LXI H,PDIR
LXI D,2*(MAXDIR+1)
MVI M,0
INX H
DCX D
MOV A,E
ORA D
JNZ $-6
LXI H,DIRBUF ;POINTS TO DIRECTORY BUFFER
SHLD OUTB
LXI H,PDIR ;POINTER TABLE
SHLD IPOINT
LDA NEWDRV
MOV E,A
DISKIO LOGIN ;LOG IN NEW DRIVE NO
DIR4: LXI H,80H ;POINTS TO INPUT BUFFER
SHLD INB
MVI C,01AH ;ISSUE SET DMA.
XCHG
CALL 5
MVI C,011H ;ISSUE DIR FIRST GET.
LXI D,DIRFCB
CALL 5
JMP DIR6
; GET NEXT DIR BUFFER.
DIR5:
MVI C,012H
CALL 5
CPI 255 ;END OF DIR?
JZ SORT ;...YES, GO SORT TABLE.
ADD A ;CONVERT # TO DISP.
ADD A
ADD A
ADD A
ADD A
ADI 80H ;ADD IN BUFFER ADDRESS.
MOV L,A
MVI H,0
SHLD INB ;SAVE PTR.
; SEE IF EOF.
DIR6: LHLD OUTB ;LOAD DESTINATION POINTER
XCHG ;PUT IT IN DE
LHLD INB ;LOAD SOURCE POINTER
MVI A,0E5H ;FLAG BYTE
CMP M ;TEST FIRST BYTE
JNZ DIR8
INX H
CMP M ;TEST SECOND BYTE
JZ SORT ;SORT DIRECTORY
JMP DIR12A
DIR8:
; IF ITS THE ZERO ENTRY, ADD IT TO TABLE.
INX H
SAVE H,D
; SCAN TABLE TO SEE IF AN EXTENT EXISTS FOR THE FILE.
LXI H,0 ;SEARCH FOR SAME NAME AND SWITCH
SHLD J ;INITIALIZE INDEX
DIR9: DLOAD PDIR,J
MOV A,H
ORA L
JZ DIR10 ;ERROR TABLE EMPTY
XCHG
LHLD INB ;POINTER TO NEW DIR ENTRY
SAVE D,H
INX H
MATCH ,,11 ;COMPARE 11 CHARAACTERS
RESTORE H,D
JZ SWITCH ;STORE NEW ENTRY OVER OLD
INDEX J,2 ;INCR INDEX BY 2
JMP DIR9
; REPLACE EXTENT IN TABLE IF ITS GREATER.
SWITCH:
CALL CLCSPC ;GET NUMBER OF GROUPS.
XCHG
LXI B,11 ;ADD IT TO CNT IN TBL.
DAD B
ADD M
MOV M,A
JNC $+5
INX H
INR M
JMP DIR12
; INSERT ENTRY IN TABLE.
DIR10: RESTORE D,H
SAVE D,H
MOVE ,,15 ;MOVE THE DIRECTORY ENTRY
RESTORE H,D
LXI H,12 ;MOVE # OF GRPS TO EX.
DAD D
CALL CLCSPC ;GET NUMBER OF CPM GROUPS.
MVI M,0 ;ZERO S1.
DCX H
MOV M,A
LDA COUNT
INR A
STA COUNT ;INCR COUNT OF DIRECTORY ENTRIES
LHLD OUTB
DSTORE 0,IPOINT ;INDEXED STORE HL
INDEX OUTB,16
INDEX IPOINT,2
JMP DIR12A
; BUMP INPUT POINTERS AND CHECK FOR END OF BUFFER.
DIR12:
RESTORE H
DIR12A:
JMP DIR5 ;READ ANOTHER BLOCK FROM DIRECTORY
; GET NUMBER OF CP/M GROUPS IN THIS EXTENT.
CLCSPC: SAVE B,D,H
LHLD INB ;POINT TO EXTENT GROUP #'S.
LXI D,16
DAD D
MVI B,0 ;ZERO COUNT.
MVI C,16 ;SET FOR MAX # OF GROUPS.
CLCLP:
MOV A,M ;GET A GROUP #.
ORA A ;ALLOCATED?
JZ $+4 ;...NO.
INR B ;...YES, BUMP COUNT.
INX H ;BUMP GROUP PTR.
DCR C ;DECR COUNT.
JNZ CLCLP ;LOOP FOR ALL ENTRIES.
MOV A,B ;GET COUNT.
RESTORE H,D,B
RET
; THIS ROUTINE PRINTS THE DIRECTORY IN 3 COLUMNS. NO OF LINES
; PRINTED IS CONTROLED BY VARIABLE LINES. ALL DIRECTORY NAMES
; ARE PRESENT IN TABLE BUT ONLY A MAXIMUM OF 3*LINES WILL BE
; PRINTED.
;
DIR14: LXI H,0
SHLD W ;INITIALIZE ALLOCATION
SHLD I ;INITIALIZE INDEX
DIR16: DLOAD PDIR,I ;INDEX LOAD POINTER
DJZ ENDFIL ;EXIT IF POINTER ZERO
CALL DIR20 ;CALL PRINT ROUTINE FOR AN ENTRY.
PRINT ' '
DLOAD PDIR+LINES*2,I ;POINTER COL 2
DJZ DIR18 ;NO PRINT IF ZERO
CALL DIR20 ;PRINT IT
PRINT ' '
DLOAD PDIR+LINES*4,I ;POINTER COL 3
DJZ DIR18
CALL DIR20 ;CALL PRINT ROUTINE
DIR18: PRINT CRLF,$
INDEX I,2 ;INCR INDEX BY 2
LXI D,LINES*2 ;CHECK INDEX LIMIT
CPHL
JZ ENDFIL ;EXIT WHEN INDEX 32
JMP DIR16 ;PRINT SOME MORE
; *** SUBROUTINE TO PRINT A SINGLE DIRECTORY ENTRY ***
;
; PRINT THE FILE NAME.
DIR20: MVI C,11 ;NAME LENGTH
DIR22: SAVE B,H ;SAVE REGISTERS
MOV A,M ;GET A CHAR.
ANI 07FH ;REMOVE POSSIBLE INDICATOR.
CHAROUT ;PUT IT TO THE CONSOLE.
RESTORE H,B ;RESTORE THE REGISTERS
INX H ;INCR NAME POINTER
DCR C ;DECR CHAR COUNT
JNZ DIR22 ;LOOP FOR LENGTH OF NAME.
; CALCULATE AND PRINT THE FILE SIZE.
DIR24:
MOV E,M ;DE = # OF ALLOCATED GROUPS
INX H
MOV D,M
XCHG
LDA DSKBSH ;CONVERT CP/M GROUP BACK TO K.
SUI 3
JZ $+8
DAD H
DCR A
JNZ $-2
SAVE H
XCHG ;ADD IT TO CUM TOTAL.
LHLD W
DAD D
SHLD W
PRINT ' '
POP H
PUSH H
LXI D,1000
CPHL
JNC DIR30
PRINT ' '
POP H
PUSH H
LXI D,100
CPHL
JNC DIR30
PRINT ' '
POP H
PUSH H
LXI D,10
CPHL
JNC DIR30
PRINT ' '
DIR30: POP H
DECOUT
PRINT 'K'
RET
;
;
; THIS ROUTINE RESTORES DRIVE B
;
FIXB: LDA NEWDRV ;CHECK DRIVE NO
ORA A
RZ ;RETURN IF DRIVE A
LDA NEWDRV ;SELECT THE DRIVE.
MOV E,A
DISKIO LOGIN
RET
;
; THIS IS THE EXIT POINT FROM THE PROGRAM. PRINT NO OF FILES AND
; SPACE REMAINING, RELOAD OLD STACK POINTER AND RETURN BACK TO CCP.
;
ENDFIL: PRINT <CR,LF,' '>
LXI H,0
LDA COUNT
MOV L,A
DECOUT
PRINT ' FILES '
LHLD MAXSTR ;GET MAX STORAGE SIZE.
DSUB W ;SUBTRACT IN-USE SIZE.
DECOUT
PRINT <'K BYTES REMAINING ON DISK',CR,LF>
EF1: LHLD OLDSTK
SPHL ;RELOAD OLD STACK POINTER
RET ;RETURN TO CCP WITHOUT REBOOT
;
DSKERR: PRINT <CR,LF,'ERROR - SELECT DRIVE A, B, C OR D'>
JMP EF1 ;EXIT
;
; THIS SECTION DOES THE ACTUAL SORTING OF THE DIRECTORY. DURING THE
; INPUT OF THE DIRECTORY NAMES, A TABLE OF ADDRESS POINTERS PDIR
; WAS CONSTRUCTED. THE SORT ROUTINE SORTS THE ADDRESS POINTERS
; RATHER THAN THE ACTUAL DIRECTORY.
; THIS IS AN IMPLEMENTATION OF C. A. R. HOARE'S QUICKSORT ALGORITHM.
; THE ALGORITHM IS VERY FAST AND GENERALLY USEFUL, HOWEVER CAUTION
; SHOULD BE USED WITH LARGE FILES. THE ALGORITHM IS RECURSIVE AND
; THE STACK SPACE REQUIRED IS PROPORTIONAL TO THE NO OF ITEMS TO BE
; SORTED.
;
SORT: LDA COUNT ;NO OF ENTRIES IN DIR
ORA A
JZ ENDFIL ;EXIT IF DIRECTORY EMPTY
DCR A
LXI H,0 ;ZERO HL
MOV L,A
DAD H
SHLD LAST ;END OF ARRAY
LXI H,0
SHLD FIRST ;START OF ARRAY
LXI H,0FFFFH
PUSH H ;FLAG FOR STACK EMPTY
LHLD FIRST
PUSH H
LHLD LAST
PUSH H ;STACK CONTAINS FIRST AND LAST INDICES
;
; NOW POP STACK AND KEEP CALLING SPLIT RECURSIVELY TILL STACK EMPTY
;
SORT2: POP H
MOV A,H
CPI 0FFH
JZ DIR14 ;GO TO PRINT ROUTINE
SHLD J
SHLD LAST
POP H
SHLD I
SHLD FIRST
CALL SPLIT
LHLD I
XCHG
LHLD FIRST
CPHL
JZ SORT4
PUSH H ;I ON STACK
DCX D
DCX D
PUSH D ;J ON STACK
SORT4: LHLD J
XCHG
LHLD LAST
CPHL
JZ SORT8
INX D
INX D
PUSH D ;NEW I ON STACK
PUSH H ;NEW J ON STACK
SORT8: JMP SORT2
;
; SPLIT SUBROUTINE DOES A SINGLE PARTITION ON AN ARRAY OF POINTERS
;
SPLIT: HALF I
XCHG
HALF J
DAD D
MOV A,L
ANI 0FEH
MOV L,A
SHLD K ;K=I+J/2
DLOAD PDIR,K
SHLD W ;W IS POINTER TO PARTITION ELEMENT OF PDIR
SPLIT2: DLOAD PDIR,I ;GET ITEM FROM LEFT
XCHG
LHLD W ;PARTITION ELEMENT
MATCH ,,11 ;CONPARE KEYS
JP SPLIT4
INDEX I,2 ;INCR I
JMP SPLIT2
SPLIT4: DLOAD PDIR,J ;GET ITEM FROM RIGHT
XCHG
LHLD W ;PARTITION ELEMENT
XCHG
MATCH ,,11 ;COMPARE KEYS
JP SPLIT6
INDEX J,-2
JMP SPLIT4 ;LOOP BACK
SPLIT6: LHLD I
XCHG
LHLD J
CPHL ;COMPARE I AND J
RZ ;RET IF I = J
DLOAD PDIR,I ;SWITCH POINTERS
SAVE H
DLOAD PDIR,J
DSTORE PDIR,I
RESTORE H
DSTORE PDIR,J
JMP SPLIT2
;
; DATA ALLOCATIONS
;
LINES EQU 18 ;LINES PER PAGE ON DISPLAY
SPACE: DB ' $' ;ASCII SPACE
CRLF: DB 0DH,0AH,24H ;ASCII CR LF
I: DW 0 ;PSEUDO INDEX REGISTER
J: DW 0 ;PSEUDO INDEX REGISTER
K: DW 0 ;PSEUDO INDEX REGISTER
FIRST: DW 0 ;START OF ARRAY
LAST: DW 0 ;END OF ARRAY
W: DW 0 ;STORAGE FOR PARTITION INDEX
DIRSIZ: DW 0 ;SIZE OF DIRECTORY IN K
MAXSTR: DW 0 ;MAXIMUM STORAGE AVAILABLE
LINE: DW 0 ;LINE NUMBER FOR LISTING
IPOINT: DW 00 ;VARIABLE BUFFER POINTER
DRVNO: DB 0 ;STORAGE FOR ORIGINALLY LOGGED DRIVE
NEWDRV: DB 0 ;STORAGE FOR NEW DRIVE NO
COUNT: DB 0 ;COUNT OF DIRECTORY ENTRIES
OLDSTK: DW 0 ;STORAGE FOR OLD STACK POINTER
ENDSTK: DS 128 ;STORAGE FOR NEW STACK
NEWSTK: DW 0 ;NEW STACK
INB: DW 0 ;STORES POINTER TO INPUT BUFFER AREA
OUTB: DW 0 ;STORES POINTER TO DIRECTORY BUFFER AREA
DPBADR: DW 0 ;ADDRESS OF DISK'S CP/M DPB
DSKBSH: DB 0 ;DISK DPBBSH VALUE
DSKBLM: DB 0 ;DISK DPBBLM VALUE
DIRFCB: DB '?','????????','???','?',0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0
PDIR DW 0 ;POINTER TABLE TO DIRECTORY
DIRBUF: EQU PDIR+(2*MAXDIR) ;START OF AREA USED TO STORE AND SORT DIRECTORY
END