home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol096
/
xdir.a86
< prev
Wrap
Text File
|
1984-04-29
|
38KB
|
1,626 lines
TITLE 'XDIR Ver 1.0 for CP/M-86'
;
; XDIR.A86 for CP/M-86, as of February 18, 1981: Kelly Smith
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
;USER OPTION SPECIFICATIONS
;
AOPT EQU TRUE ;TRUE TO ALLOW SEARCHING ALL USER AREAS
DOPT EQU TRUE ;TRUE TO ALLOW SEARCHING ALL DRIVES ON-LINE
FOPT EQU TRUE ;TRUE TO ALLOW FILE OUTPUT OPTION
NOPT EQU TRUE ;TRUE TO ALLOW DISABLING PAGE PAUSE OPTION
PGPAWZ EQU TRUE ;TRUE FOR PAUSE AFTER EACH PAGE
POPT EQU TRUE ;TRUE TO ALLOW PRINTER OPTION
REPERR EQU TRUE ;TRUE TO REPORT COMMAND LINE OPTION ERRORS
REPSIZ EQU TRUE ;TRUE TO REPORT FILE SIZES
SOPT EQU TRUE ;TRUE TO ALLOW SYSTEM FILE OPTION
UOPT EQU TRUE ;TRUE TO ALLOW USER NUMBER OPTION
DELIM EQU 7CH ;FENCE (DELIMITER) CHARACTER (VERTICAL BAR)
BIGCRT EQU TRUE ;TRUE = 24/80 DISPLAY, FALSE = 16/64 DISPLAY
NPL EQU 4 ;# OF NAMES PER LINE (MAX OF 3 FOR 64X16)
; (MAX OF 4 FOR 80X24)
LPS EQU 20 ;# OF LINES PER SCREEN (MAX OF 12 FOR 64X16)
; (MAX OF 20 FOR 80X24)
;
; BDOS EQUATES
;
RDCHR EQU 1 ;READ CHAR FROM CONSOLE
WRCHR EQU 2 ;WRITE CHAR TO CONSOLE
CONST EQU 11 ;CHECK CONS STAT
RESET EQU 13 ;RESET DISK SYSTEM
SELDSK EQU 14 ;SELECT DISK
OPEN EQU 15 ;0FFH=NOT FOUND
CLOSE EQU 16 ; " "
SEARCH EQU 17 ; " "
NEXT EQU 18 ; " "
READ EQU 20 ;NOT 0 = EOF
WRITE EQU 21 ;NOT 0 = DISK FULL
MAKE EQU 22 ;0FFH = DIRECTORY FULL
CURDSK EQU 25 ;GET CURRENTLY LOGGED DISK NAME
SETDMA EQU 26 ;SET CURRENT DMA
GALLOC EQU 27 ;GET ADDRESS OF ALLOCATION VECTOR
CURDPB EQU 31 ;GET CURRENT DISK PARAMETERS
CURUSR EQU 32 ;GET CURRENTLY LOGGED USER NUMBER
BASE EQU 0
TPA EQU 100H
FCB EQU BASE+5CH
;
M EQU Byte Ptr 0[BX]
;
; BEGIN EXECUTABLE PROGRAM CODE
;
ORG TPA
START: MOV DL,0FFH ;GET CURRENT USER NUMBER
MOV CL,CURUSR
CALL CPM
MOV Byte Ptr OLDUSR,AL ;INITIALIZE STARTUP USER NUMBER
MOV Byte Ptr NEWUSR,AL ;..AND MAKE NEW USER MATCH IT
MOV Byte Ptr BASUSR,AL ;SAVE EXTRA COPY FOR MULTI-DISK DIRECTORIES
MOV CL,CURDSK
CALL CPM ;GET CURRENT DISK NR
MOV Byte Ptr OLDDSK,AL ;SAVE FOR RESET IF NEEDED
INC AL
MOV Byte Ptr OUTFCB,AL ;SET DIRECTORY OUTPUT FILE DRIVE
MOV BX,FCB
MOV AL,M ;GET DRIVE NAME FOR DIRECTORY SEARCH
OR AL,AL ;ANY SPECIFIED?
JNZ START2 ;YES SKIP NEXT ROUTINE
MOV AL,Byte Ptr OLDDSK ;OTHERWISE, GET DEFAULT DISK
INC AL
START2: MOV M,AL ;PUT THE ABSOLUTE DRIVE CODE IN DIRECTORY FCB
;
; IF AT LEAST ONE OPTION IS ALLOWED, SCAN THE COMMAND LINE FOR THE
; OPTION FIELD DELIMITER. THE OPTION FIELD DELIMITER IS CONSIDERED
; VALID ONLY IF IT IS PRECEDED BY AT LEAST 1 SPACE (OTHERWISE, IT
; MAY BE PART OF THE DIRECTORY FILENAME). ANY UNRECOGNIZED OPTIONS
; OR ILLEGAL USER NUMBERS WILL BE FLAGGED OR IGNORED (SEE REPERR).
; (WE SCAN THE COMMAND LINE BUFFER RATHER THAN THE 2ND DEFAULT FCB
; BECAUSE ALL 8 OPTIONS PLUS A 2 DIGIT USER NUMBER WON'T FIT IN
; THE FCB NAME FIELD).
;
MOV BX,80H ;SET COMMAND LINE BUFFER POINTER
MOV CH,M ;GET LENGTH OF COMMAND LINE BUFFER
;
; SEARCH FOR THE COMMAND LINE DELIMITER. IF NOT FOUND, ASSUME NO OPTIONS.
;
SCNDOL: LAHF
INC BX
SAHF
DEC CH
JNS L_1
JMP CKREST ;EXIT IF COMMAND LINE BUFFER EMPTY
L_1:
MOV AL,M
CMP AL,'$'
JNZ SCNDOL
DEC BX ;'$' FOUND - MAKE SURE SPACE PRECEDES IT
MOV AL,M
INC BX
CMP AL,' '
JNZ SCNDOL ;NO SPACE - IGNORE "$" AND SEARCH AGAIN
;
; VALID DELIMITER FOUND. SCAN THE REST OF THE BUFFER FOR OPTIONS. ERRORS
; PAST THIS POINT WILL CAUSE AN ABORT IF THE COMMAND LINE ERROR OPTION IS
; ENABLED. OTHERWISE, THE DUD OPTION WILL BE IGNORED AND SD WILL ATTEMPT
; TO CONTINUE STUMBLING THROUGH THE REST OF THE FIELD.
;
XCHG BX,DX ;GET OPTION FIELD POINTER TO DE
SCNOPT: LAHF ;BUMP TO NEXT OPTION FIELD CHARACTER
INC DX
SAHF
DEC CH ;DOCK CHARACTERS LEFT IN OPTION FIELD
JNS L_2
JMP CKREST ;IF OPTION FIELD EXHAUSTED, EXIT
L_2:
SCNAGN: MOV SI,DX ;GET THE NEXT OPTION CHARACTER
MOV AL,[SI]
CMP AL,' ' ;DO WE HAVE A SPACE?
JZ SCNOPT ;IGNORE IT IF SO
MOV BX,(Offset OTBL)-1 ;GET BASE OF OPTION LOOKUP TABLE
MOV CL,(Offset OEND)-(Offset OTBL)+1 ;GET LENGTH OF OPTION LOOKUP TABLE
NOMACH: INC BX ;BUMP TO NEXT OPTION TABLE CHARACTER
DEC CL ;ARE WE OUT OF THE TABLE?
JZ CK4USR ;IF SO, CHECK FOR USER OPTION
CMP AL,M ;COMPARE OUR CHARACTER WITH OPTION TABLE
JNZ NOMACH ;EXIT IF NO MATCH
MOV M,0 ;OTHERWISE, ACTIVATE THE FLAG
JMPS SCNOPT ;..AND GO GET THE NEXT OPTION CHARACTER
;
; IF OPTION CHARACTER DOESN'T MATCH THE TABLE, SEE IF WE HAVE A USER
; OPTION.
;
IF UOPT
CK4USR: ;CHECK FOR USER NUMBER OPTION
CMP AL,'U'
JNZ CLERR ;LAST OPTION, SO BAD DEAL IF THAT AIN'T IT
UAGN: LAHF ;BUMP TO USER NUMBER DIGIT
INC DX
SAHF
DEC CH
JS CLERR ;ERROR IF NOTHING LEFT
MOV SI,DX ;GET DECIMAL DIGIT
MOV AL,[SI]
CMP AL,' ' ;IGNORE LEADING SPACES
JZ UAGN
SUB AL,30H ;SUBTRACT ASCII BIAS
JB CLERR ;ERROR IF < 0
CMP AL,10
JNB CLERR ;ERROR IF > 9
MOV Byte Ptr NEWUSR,AL ;SAVE USER NUMBER AS IT MAY BE ONLY 1 DIGIT
MOV Byte Ptr BASUSR,AL ;DUPLICATE IT IF MULTI-DISK MODE
LAHF ;BUMP TO POSSIBLE 2ND DIGIT OF USER NUMBER
INC DX
SAHF
DEC CH
JS CKREST ;IF NO MORE BUFFER, EXIT WITH COMPLETE USER #
MOV SI,DX ;ELSE, CHECK FOR ANOTHER DIGIT
MOV AL,[SI]
SUB AL,30H
JB SCNAGN ;IF NEXT CHAR NOT NUMERIC, ITS NOT PART OF
CMP AL,10 ;..USER NUMBER SO GO CHECK FOR ANOTHER OPTION
JNB SCNAGN
MOV BL,AL ;SAVE UNITS DIGIT
MOV AL,Byte Ptr NEWUSR ;GET TENS DIGIT
ADD AL,AL ;MULTIPLY BY 10
MOV BH,AL
ADD AL,AL
ADD AL,AL
ADD AL,BH
ADD AL,BL ;COMBINE WITH UNITS DIGIT
MOV Byte Ptr NEWUSR,AL ;SAVE THE TOTAL USER NUMBER
MOV Byte Ptr BASUSR,AL ;DUPLICATE IT IF MULTI-DISK MODE
JMP SCNOPT ;CONTINUE SCANNING
ENDIF
;
; IF COMMAND LINE ERROR OPTION ENABLED, PLAYBACK THE COMMAND LINE UP
; TO THE CHARACTER THAT WE GAGGED ON AND EXIT. IF REPERR IS NOT ENABLED,
; THEN CONTINUE AS IF NOTHING WERE AMISS TO AVOID ACKNOWLEDGING THAT
; SOME OPTIONS ARE AVAILABLE.
;
IF REPERR
CLERR:
XOR AL,AL
LAHF ;TAG END OF COMMAND LINE WITH TERMINATOR
INC DX
SAHF
MOV SI,DX
MOV [SI],AL
CALL CRLF
MOV DX,(Offset ERRMS2)
CALL PRINT
MOV DX,(Offset ERRTAG)
CALL PRINT
MOV BX,81H ;PLAYBACK BAD COMMAND LINE TO ERROR POINT
CLELP: MOV AL,M
OR AL,AL
JZ CLEX
CALL SEND_CHAR
INC BX
JMPS CLELP
CLEX: MOV AL,'?' ;TAG LINE WITH A '?' FIELD
CALL SEND_CHAR
CALL CRLF ;SPACE DOWN 1 MORE LINE
JMP EXIT ;..AND RETURN TO CP/M
ENDIF
;
; OPTIONS INPUT OR NOT SPECIFIED. IF RESET OPTION SPECIFIED, DO IT NOW.
;
CKREST:
MOV AL,Byte Ptr ROPFLG ;IF RESET FLAG SET, RESET DISK SYSTEM BEFORE
OR AL,AL ;..STARTING TO UPDATE ALLOCATION VECTORS
MOV CL,RESET
JNZ L_3
CALL CPM
L_3:
;
; VALIDATE DRIVE CODE AND USER AREA NUMBERS FROM THE DRIVE TABLE.
;
NOOPT: MOV DX,(Offset DREMSG) ;GET THE DRIVE/USER ERROR MESSAGE
PUSH DX
MOV AL,Byte Ptr .FCB ;GET DIRECTORY DRIVE CODE
DEC AL ;NORMALIZE TO RANGE OF 0-15
CMP AL,(Offset HIDRV)-(Offset LODRV) ;COMPARE WITH MAXIMUM DRIVES ON-LINE
JNAE L_4
JMP ERXIT ;TAKE DRIVE ERROR EXIT IF OUT OF RANGE
L_4:
MOV BX,(Offset USRMSG) ;SWITCH TO USER # ERROR MESSAGE
MOV BP,SP
XCHG BX,[BP]
MOV DL,AL ;USE DRIVE CODE AS INDEX INTO TABLE
MOV DH,0
MOV BX,(Offset LODRV) ;POINT TO BASE OF DRIVE/USER TABLE
ADD BX,DX
MOV AL,M ;GET THE MAXIMUM USER # FOR THIS DRIVE
AND AL,0FH ;MAKE SURE ITS IN RANGE 0 - 15
MOV Byte Ptr MAXUSR,AL ;SAVE IT FOR LATER
MOV BX,(Offset NEWUSR) ;POINT TO THE DIRECTORY USER AREA
CMP AL,M ;COMPARE IT WITH THE MAXIMUM
JNB L_5
JMP ERXIT ;TAKE ERROR EXIT IF USER NUMBER ILLEGAL
L_5:
POP DX ;DESTROY ERROR MESSAGE POINTER
MOV BX,FCB+1 ;POINT TO NAME
MOV AL,M ;ANY SPECIFIED?
CMP AL,' '
JNZ GOTFCB
;
; NO FCB - MAKE FCB ALL '?'
;
MOV CH,11 ;FN+FT COUNT
QLOOP: MOV M,'?' ;STORE '?' IN FCB
LAHF
INC BX
SAHF
DEC CH
JNZ QLOOP
GOTFCB: MOV AL,'?' ;FORCE WILD EXTENT
MOV Byte Ptr .FCB+12,AL
CALL SETSRC ;SET DMA FOR BDOS MEDIA CHANGE CHECK
MOV BX,FCB ;POINT TO FCB DRIVE CODE FOR DIRECTORY
MOV DL,M ;GET THE DRIVE CODE OUT OF THE FCB
DEC DL ;NORMALIZE DRIVE CODE FOR SELECT
MOV CL,SELDSK ;SELECT THE DIRECTORY DRIVE TO RETRIEVE
CALL CPM ;..THE PROPER ALLOCATION VECTOR
MOV CL,curdpb ;get disk parameter block
INT 224
INC BX ;point to block shift
INC BX
MOV AL,ES: M ;[AL] = block shift = log2(records/block)
SUB AL,3 ;[AL] = log2(kbytes/block)
MOV Byte Ptr blkshf,AL
INC BX ;point to disk size
mov al,es: m ;get block mask, and save it
mov Byte Ptr blkmsk,al
INC BX
INC BX
MOV DL,ES: M
INC BX
MOV DH,ES: M
MOV Word Ptr dsksiz,DX ;dsksiz = blocks/dsk
;
;
; Now get amount used on disk
;
allctd: MOV CL,galloc ;get allocation vector address
INT 224
;
push ds ;save the data segment at all cost...
MOV DX,Word Ptr dsksiz ;get blocks/disk
mov si,bx ;make indirect pointer
test dl,7 ;big blocks or little blocks?
jz divlp1
add dx,8
divlp1: mov cl,3 ;the great divide...
shr dx,cl
mov cx,dx
mov dl,0
push es ;trick to get to proper data segment
pop ds
cntit: lods ds: m ;nice way to get data to [AL] pointed by 0[BX] from [SI]
;...with nifty increment of pointer at [SI]
mov bx,cx
mov cx,8 ;scan thru 8 bits for 1's set
try1: shr al,1
jnb not1
inc dx ;got a live one, bump 'used' counter
not1: loop try1
mov cx,bx
loop cntit
pop ds ;restore to orginal data segment
;
MOV BX,Word Ptr dsksiz ;[BX] = blocks/disk-1, [DX] = blocks used
inc bx ;bump for actual disk size
MOV AL,BL ;do a sixteen bit subtract
SUB AL,DL
MOV BL,AL
MOV AL,BH
SBB AL,DH
MOV BH,AL ;[BX] = unused blocks
MOV AL,Byte Ptr blkshf ;now convert from blocks to kilobytes
OR AL,AL
shftit: JZ savit
SHL BX,1
DEC AL
JMPS shftit
;
savit: MOV Word Ptr freeby,BX ;[BX] = kbytes unused
;
;
; REENTER HERE ON SUBSEQUENT PASSES WHILE IN THE ALL-USERS MODE
;
SETTBL: MOV BX,Word Ptr dsksiz ;GET DIRECTORY MAXIMUM AGAIN
LAHF ;DIRECTORY SIZE IS dsksiz+1
INC BX
SAHF
SHL BX,1 ;DOUBLE DIRECTORY SIZE
MOV DX,(Offset ORDER) ;TO GET SIZE OF ORDER TABLE
LAHF ;ALLOCATE ORDER TABLE
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
MOV Word Ptr TBLOC,BX ;NAME TABLE BEGINS WHERE ORDER TABLE ENDS
MOV Word Ptr NEXTT,BX
XCHG BX,DX
;
;+++ MAY HAVE TO CHECK FOR AVAILABLE MEMORY HERE +++
;
IF UOPT
MOV AL,Byte Ptr NEWUSR ;GET USER AREA FOR DIRECTORY
MOV DL,AL
MOV CL,CURUSR ;GET THE USER FUNCTION
CALL CPM ;..AND SET NEW USER NUMBER
ENDIF
;
; LOOK UP THE FCB IN THE DIRECTORY
;
SFIRST: MOV BX,0
MOV Word Ptr COUNT,BX ;INITIALIZE MATCH COUNTER
MOV Word Ptr TOTFIL,BX ; " TOTAL FILE COUNTER
MOV Word Ptr TOTSIZ,BX ; " TOTAL SIZE COUNTER
CALL SETSRC ;SET DMA FOR DIRECTORY SEARCH
MOV CL,SEARCH ;GET 'SEARCH FIRST' FUNCTION
JMPS LOOK ;..AND GO SEARCH FOR 1ST MATCH
;
; READ MORE DIRECTORY ENTRIES
;
MORDIR: MOV CL,NEXT ;SEARCH NEXT
LOOK: MOV DX,FCB
CALL CPM ;READ DIRECTORY ENTRY
INC AL ;CHECK FOR END (0FFH)
JNZ L_6
JMP SPRINT ;IF NO MORE, SORT & PRINT WHAT WE HAVE
L_6:
;
; POINT TO DIRECTORY ENTRY
;
SOME: DEC AL ;UNDO PREV 'INR A'
AND AL,3 ;MAKE MODULUS 4
ADD AL,AL ;MULTIPLY...
ADD AL,AL ;..BY 32 BECAUSE
ADD AL,AL ;..EACH DIRECTORY
ADD AL,AL ;..ENTRY IS 32
ADD AL,AL ;..BYTES LONG
MOV BX,BASE+81H ;POINT TO BUFFER
;
;SKIP TO FN/FT
;
ADD AL,BL ;POINT TO ENTRY
ADD AL,9 ;POINT TO SYS BYTE
MOV BL,AL ;SAVE (CAN'T CARRY TO H)
IF SOPT
MOV AL,Byte Ptr SOPFLG ;DID USER REQUEST SYS FILES?
OR AL,AL
JZ SYSFOK
ENDIF
MOV AL,M ;GET SYS BYTE
OR AL,AL ;CHECK BIT 7
JS MORDIR ;SKIP THAT FILE
SYSFOK: MOV AL,BL ;GO BACK NOW
SUB AL,10 ;BACK TO USER NUMBER (ALLOC FLAG)
MOV BL,AL ;HL POINTS TO ENTRY NOW
MOV AL,Byte Ptr NEWUSR ;GET CURRENT USER
CMP AL,M
JNZ MORDIR ;IGNORE IF DIFFERENT
INC BX
;
; MOVE ENTRY TO TABLE
;
XCHG BX,DX ;ENTRY TO DE
MOV BX,Word Ptr NEXTT ;NEXT TABLE ENTRY TO HL
MOV CH,12 ;ENTRY LENGTH (NAME, TYPE, EXTENT)
TMOVE: MOV SI,DX ;GET ENTRY CHAR
MOV AL,[SI]
AND AL,7FH ;REMOVE ATTRIBUTES
MOV M,AL ;STORE IN TABLE
LAHF
INC DX
SAHF
LAHF
INC BX
SAHF
DEC CH ;MORE?
JNZ TMOVE
LAHF
INC DX
SAHF
LAHF ;POINT TO SECTOR COUNT
INC DX
SAHF
MOV SI,DX ;GET IT
MOV AL,[SI]
MOV M,AL ;STORE IN TABLE
LAHF
INC BX
SAHF
MOV Word Ptr NEXTT,BX ;SAVE UPDATED TABLE ADDR
XCHG BX,DX
MOV BX,Word Ptr COUNT ;BUMP THE # OF MATCHES MADE
LAHF
INC BX
SAHF
MOV Word Ptr COUNT,BX
MOV BX,13 ;SIZE OF NEXT ENTRY
LAHF
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
XCHG BX,DX ;FUTURE NEXTT IS IN DE
JMP MORDIR ;ATTEMPT TO GET NEXT DIRECTORY ENTRY
;
; SORT AND PRINT
;
SPRINT:
CALL SETFOP ;RETURN TO FILE OUTPUT DMA & USER #
MOV BX,Word Ptr COUNT ;GET FILE NAME COUNT
MOV AL,BL
OR AL,BH ;ANY FOUND?
JNZ L_7
JMP PRTOTL ;EXIT IF NO FILES FOUND
L_7:
PUSH BX ;SAVE FILE COUNT
MOV Byte Ptr SUPSPC,AL ;ENABLE LEADING ZERO SUPPRESSION
;
; INITIALIZE THE ORDER TABLE
;
MOV BX,Word Ptr TBLOC ;GET START OF NAME TABLE
XCHG BX,DX ;INTO DE
MOV BX,(Offset ORDER) ;POINT TO ORDER TABLE
MOV CX,13 ;ENTRY LENGTH
BLDORD: MOV M,DL ;SAVE LOW ORDER ADDRESS
INC BX
MOV M,DH ;SAVE HIGH ORDER ADDRESS
INC BX
XCHG BX,DX ;TABLE ADDR TO HL
ADD BX,CX ;POINT TO NEXT ENTRY
XCHG BX,DX
MOV BP,SP ;SAVE TBL ADDR, FETCH LOOP COUNTER
XCHG BX,[BP]
DEC BX ;COUNT DOWN LOOP
MOV AL,BL
OR AL,BH ;MORE?
MOV BP,SP ;(RESTORE TBL ADDR, SAVE COUNTER)
XCHG BX,[BP]
JNZ BLDORD ;YES, GO DO ANOTHER ONE
POP BX ;CLEAN LOOP COUNTER OFF STACK
MOV BX,Word Ptr COUNT ;GET COUNT
MOV Word Ptr SCOUNT,BX ;SAVE AS # TO SORT
DEC BX ;ONLY 1 ENTRY?
MOV AL,BL
OR AL,BH
JNZ L_8
JMP DONE ;YES, SO SKIP SORT
L_8:
;
; THIS SORT ROUTINE IS ADAPTED FROM SOFTWARE TOOLS
; BY KERNIGAN AND PLAUGHER.
;
SORT: MOV BX,Word Ptr SCOUNT ;NUMBER OF ENTRIES
SORT0: OR AL,AL ;CLEAR CARRY
MOV AL,BH ;GAP=GAP/2
RCR AL,1
MOV BH,AL
MOV AL,BL
RCR AL,1
MOV BL,AL
OR AL,BH ;IS IT ZERO?
JNZ L_9
JMP DONE ;THEN NONE LEFT
L_9:
MOV AL,BL ;MAKE GAP ODD
OR AL,01
MOV BL,AL
MOV Word Ptr GAP,BX
INC BX ;I=GAP+1
SORT2: MOV Word Ptr I,BX
XCHG BX,DX
MOV BX,Word Ptr GAP
MOV AL,DL ;J=I-GAP
SUB AL,BL
MOV BL,AL
MOV AL,DH
SBB AL,BH
MOV BH,AL
SORT3: MOV Word Ptr J,BX
XCHG BX,DX
MOV BX,Word Ptr GAP ;JGAP=J+GAP
LAHF
ADD BX,DX
SAHF
MOV Word Ptr JGAP,BX
MOV AL,12 ;COMPARE 12 CHARS
CALL COMPARE ;COMPARE (J) AND (JG)
JNS SORT5 ;IF A(J)<=A(JG)
MOV BX,Word Ptr J
XCHG BX,DX
MOV BX,Word Ptr JGAP
CALL SWAP ;EXCHANGE A(J) AND A(JG)
MOV BX,Word Ptr J ;J=J-GAP
XCHG BX,DX
MOV BX,Word Ptr GAP
MOV AL,DL
SUB AL,BL
MOV BL,AL
MOV AL,DH
SBB AL,BH
MOV BH,AL
JS SORT5 ;IF J>0 GOTO SORT3
OR AL,BL ;CHECK FOR ZERO
JZ SORT5
JMPS SORT3
SORT5: MOV BX,Word Ptr SCOUNT ;FOR LATER
XCHG BX,DX
MOV BX,Word Ptr I ;I=I+1
INC BX
MOV AL,DL ;IF I<=N GOTO SORT2
SUB AL,BL
MOV AL,DH
SBB AL,BH
JS L_10
JMP SORT2
L_10:
MOV BX,Word Ptr GAP
JMP SORT0
;
; SORT IS ALL DONE - PRINT ENTRIES
;
DONE: MOV AL,Byte Ptr FOPFLG
OR AL,AL
JZ L_11
JMP NOOUT ;IF FILE OUTPUT, FALL THROUGH WITH A=0
L_11:
;
; IF ALL USER OPTION ENABLED, AND WE'RE NOT ON THE FIRST PASS, THEN THE
; OUTPUT FILE IS ALREADY OPEN AND POSITIONED, SO WE CAN SKIP THE OPEN.
;
MOV BX,(Offset OPNFLG) ;POINT TO OUTPUT FILE OPEN FLAG
CMP AL,M ;A=0, SET Z IF OPNFLG=0 ALSO
JZ L_12
JMP NOOUT ;IF OPNFLG NOT ZERO, SKIP OPEN
L_12:
DEC M ;ELSE, MAKE OPNFLG NOT ZERO AND OPEN
;
; FIRST PASS ON FILE APPEND - PREPARE XDIR.DIR TO RECEIVE NEW OR APPENDED
; OUTPUT.
;
MOV DX,(Offset OUTFCB) ;DOES OUTPUT FILE ALREADY EXIST?
MOV CL,SEARCH
CALL CPM
INC AL
JNZ OPENIT ;IF IT DOES, THEN OPEN IT FOR PROCESSING
MOV CL,MAKE ;OTHERWISE, CREATE THE OUTPUT FILE
CALL CPM
INC AL
JZ L_13
JMP NOOUT ;CONTINUE IF OPEN SUCCESSFUL
L_13:
;
; IF MAKE OR OPEN FAILS, DECLARE ERROR
;
OPNERR: CALL ERXIT
DB 'OPE','N' OR 80H
;
WRTERR: CALL ERXIT
DB 'WRIT','E' OR 80H
;
; OUTPUT FILE ALREADY EXISTS - OPEN IT AND POSITION TO THE LAST
; RECORD OF THE LAST EXTENT.
;
OPENIT: MOV CL,OPEN ;OPEN 1ST EXTENT OF OUTPUT FILE
CALL CPM
INC AL
JZ OPNERR ;BAD DEAL IF 1ST WON'T OPEN
OPNMOR: MOV AL,Byte Ptr OUTFCB+15
CMP AL,128
JB LSTEXT ;IF RC<128, THIS IS LAST EXTENT
MOV BX,(Offset OUTFCB)+12
INC M ;ELSE, BUMP TO NEXT EXTENT
MOV CL,OPEN ;..AND TRY TO OPEN IT
CALL CPM
INC AL
JNZ OPNMOR ;CONTINUE OPENING EXTENTS TIL NO MORE
DEC M ;THEN, REOPEN PRECEDING EXTENT
MOV CL,OPEN
CALL CPM
MOV AL,Byte Ptr OUTFCB+15 ;GET RC FOR THE LAST EXTENT
;
; AT THIS POINT, OUTFCB IS OPENED TO THE LAST EXTENT OF THE FILE,
; SO READ IN THE LAST RECORD IN THE LAST EXTENT.
;
LSTEXT: OR AL,AL ;IS THIS EXTENT EMPTY?
JZ NOOUT ;IF SO, THEN WE'RE STARTING A CLEAN SLATE
DEC AL ;NORMALIZE RECORD COUNT
MOV Byte Ptr OUTFCB+32,AL ;SET RECORD NUMBER TO READ
MOV CL,READ ;..AND READ LAST RECORD OF FILE
CALL CPM
OR AL,AL ;WAS READ SUCCESSFUL?
JZ RDOK ;IF SO, PROCEED TO SCAN FOR EOF MARK
APERR: CALL ERXIT
DB 'APPEN','D' OR 80H
;
; WE NOW HAVE THE LAST RECORD IN THE FILE IN OUR BUFFER.
; SCAN THE LAST RECORD FOR THE EOF MARK, INDICATING WHERE
; WE CAN START ADDING DATA.
;
RDOK: MOV BX,(Offset OUTBUF) ;POINT TO START OF OUTPUT BUFFER
MOV CH,128 ;GET LENGTH OF OUTPUT BUFFER
SCAN: MOV AL,M
CMP AL,'Z'-40H ;HAVE WE FOUND END OF FILE?
JZ RESCR ;IF SO, SAVE POINTERS AND RESET CR
LAHF
INC BX
SAHF
DEC CH
JNZ SCAN ;OTHERWISE, KEEP LOOKING TIL END OF BUFFER
;
; IF WE FIND AN EXPLICIT EOF MARK IN THE LAST BUFFER (OR AN IMPLIED EOF
; IF THE LAST RECORD IS FULL), MOVE THE FCB RECORD AND EXTENT POINTERS
; BACK TO CORRECT FOR THE READ OPERATION SO THAT OUR FIRST WRITE OPERATION
; WILL EFFECTIVELY REPLACE THE LAST RECORD OF THE XDIR.DIR FILE.
;
RESCR: PUSH BX ;SAVE EOF BUFFER POINTER
PUSH CX ;SAVE EOF BUFFER REMAINING
MOV BX,(Offset OUTFCB)+32 ;GET CURRENT RECORD AGAIN
DEC M ;DOCK IT
JNS SAMEXT ;IF CR >=0, WE'RE STILL IN SAME EXTENT
MOV BX,(Offset OUTFCB)+12 ;ELSE, MOVE TO PREVIOUS EXTENT
DEC M
MOV CL,OPEN ;THEN, REOPEN THE PREVIOUS EXTENT
CALL CPM
INC AL
JZ APERR ;APPEND POSITION ERROR IF WE CAN'T REOPEN
MOV AL,Byte Ptr OUTFCB+15 ;ELSE, POSITION TO LAST RECORD OF EXTENT
DEC AL
MOV Byte Ptr OUTFCB+32,AL
SAMEXT: POP AX ;RECALL WHERE EOF IS IN BUFFER
XCHG AL,AH
SAHF
MOV Byte Ptr BUFCNT,AL ;..AND SET BUFFER COUNTER
POP BX ;RECALL NEXT BUFFER POINTER
MOV Word Ptr BUFPNT,BX ;.. AND SET POINTER FOR FIRST ADDITION
NOOUT: MOV BX,(Offset ORDER) ;INITIALIZE ORDER TABLE POINTER
MOV Word Ptr NEXTT,BX
JMP NEWLIN ;START NEW LINE AND OUTPUT THE FILES
;
; OUTPUT THE DIRECTORY FILES WE'VE MATCHED.
;
ENTRY: MOV BX,Word Ptr COUNT
DEC BX ;DOCK FILE COUNT
MOV Word Ptr COUNT,BX
MOV AL,BH ;IS THIS THE LAST FILE?
OR AL,BL
JZ OKPRNT ;IF COUNT=0, LAST FILE SO SKIP COMPARE
;
; COMPARE EACH ENTRY TO MAKE SURE THAT IT ISN'T PART OF A MULTIPLE
; EXTENT FILE. GO ONLY WHEN WE HAVE THE LAST EXTENT OF THE FILE.
;
PUSH CX ;SAVE NPL
CALL CKABRT ;CHECK FOR ABORT CODE FROM KEYBOARD
MOV BX,Word Ptr NEXTT
MOV AL,11
CALL COMPR ;DOES THIS ENTRY MATCH NEXT ONE?
POP CX ;RECALL NPL
JNZ OKPRNT ;NO, PRINT IT
INC BX
INC BX ;SKIP SINCE HIGHEST EXTENT COMES LAST IN LIST
MOV Word Ptr NEXTT,BX
JMPS ENTRY ;LOOP BACK FOR NEXT LOWEST EXTENT
;
; VALID ENTRY OBTAINED - SPIT IT OUT.
;
OKPRNT: MOV BX,Word Ptr NEXTT ;GET ORDER TABLE POINTER
MOV DL,M ;GET LOW ORDER ADDRESS
LAHF
INC BX
SAHF
MOV DH,M ;GET HIGH ORDER ADDRESS
LAHF
INC BX
SAHF
MOV Word Ptr NEXTT,BX ;SAVE UPDATED TABLE POINTER
XCHG BX,DX ;TABLE ENTRY TO HL
MOV CH,8 ;FILE NAME LENGTH
CALL TYPEIT ;TYPE FILENAME
MOV AL,'.' ;PERIOD AFTER FN
CALL SEND_CHAR
MOV CH,3 ;DISPLAY 3 CHARACTERS OF FILETYPE
CALL TYPEIT
;
; COMPUTE THE SIZE OF THE FILE AND UPDATE OUR SUMMARY DATUM.
;
MOV DL,M ;GET EXTENT #
MOV DH,0
INC BX
MOV AL,M ;GET SECTOR COUNT OF LAST EXTENT
XCHG BX,DX
SHL BX,1 ;# OF EXTENTS TIMES 16K
SHL BX,1
SHL BX,1
SHL BX,1
XCHG BX,DX ;SAVE IN DE
MOV BX,(Offset BLKMSK)
ADD AL,M ;ROUND LAST EXTENT TO BLOCK SIZE
ROR AL,1
ROR AL,1 ;CONVERT FROM SECTORS TO K
ROR AL,1
AND AL,1FH
MOV BL,AL ;ADD TO TOTAL K
MOV BH,0
ADD BX,DX
MOV AL,Byte Ptr BLKMSK ;GET SECTORS/BLK-1
ROR AL,1
ROR AL,1 ;CONVERT TO K/BLK
ROR AL,1
AND AL,1FH
NOT AL ;USE TO FINISH ROUNDING
AND AL,BL
MOV BL,AL
XCHG BX,DX ;SAVE FILE SIZE IN DE
MOV BX,Word Ptr TOTSIZ
LAHF ;ADD TO TOTAL USED
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
MOV Word Ptr TOTSIZ,BX
MOV BX,Word Ptr TOTFIL ;INCREMENT FILE COUNT
LAHF
INC BX
SAHF
MOV Word Ptr TOTFIL,BX
XCHG BX,DX ;GET BACK FILE SIZE
;
; IF REPORT SIZE ENABLED, OUTPUT THE SIZE OF THE INDIVIDUAL FILE.
;IF FILE SIZE REPORT WANTED
;
CALL DECPRT ;..GO PRINT IT
MOV AL,'k' ;..AND FOLLOW WITH K SIZE
CALL SEND_CHAR
;
; ONE FILE OUTPUT - TEST TO SEE IF WE HAVE TO OUTPUT ANOTHER ONE.
;
MOV BX,Word Ptr COUNT ;GET CURRENT FILE COUNTER AND TEST IT
MOV AL,BH
OR AL,BL
JNZ L_14
JMP PRTOTL ;IF NO MORE FILES, EXIT TO SUMMARY OUTPUT
L_14:
;
; AT LEAST ONE MORE FILE TO OUTPUT - CAN WE PUT IT ON THE CURRENT LINE?
;
DEC CL
LAHF
XCHG AL,AH
PUSH AX
JZ L_15
CALL FENCE ;IF ROOM LEFT, OUTPUT THE FENCE CHARACTER
L_15:
POP AX
XCHG AL,AH
SAHF
JZ L_16
JMP ENTRY ;.. AND GO OUTPUT ANOTHER FILE
L_16:
;
; CURRENT LINE FULL, START A NEW ONE.
;
NEWLIN: MOV CL,NPL ;RESET NAMES PER LINE COUNTER
CALL CRLF ;SPACE DOWN TO NEXT LINE
MOV AL,Byte Ptr .FCB ;.. PRECEDE NEW LINE WITH DRIVE NAME
ADD AL,'A'-1
CALL SEND_CHAR
MOV AL,':' ;TAG DRIVE LETTER WITH A COLON AND SPACE
CALL SEND_CHAR
JMP ENTRY ;GO BACK AND OUTPUT ANOTHER FILE
;
;IF REPORTING USER NUMBERS
;
; PRINT HL IN DECIMAL WITH LEADING ZERO SUPPRESSION
;
DECPRT: SUB AL,AL ;CLEAR LEADING ZERO FLAG
MOV Byte Ptr LZFLG,AL
MOV DX,-1000 ;PRINT 1000'S DIGIT
CALL DIGIT
MOV DX,-100 ;ETC.
CALL DIGIT
MOV DX,-10
CALL DIGIT
MOV AL,'0' ;GET 1'S DIGIT
ADD AL,BL
JMP SEND_CHAR
;
DIGIT: MOV CH,'0' ;START OFF WITH ASCII 0
DIGLP: PUSH BX ;SAVE CURRENT REMAINDER
ADD BX,DX ;SUBTRACT
JNB DIGEX ;QUIT ON OVERFLOW
POP AX ;THROW AWAY REMAINDER
INC CH ;BUMP DIGIT
JMPS DIGLP ;LOOP BACK
DIGEX: POP BX ;RESTORE POINTER
MOV AL,CH
CMP AL,'0' ;ZERO DIGIT?
JNZ DIGNZ ;NO, TYPE IT
MOV AL,Byte Ptr LZFLG ;LEADING ZERO?
OR AL,AL
MOV AL,'0'
JZ L_17
JMP SEND_CHAR ;PRINT DIGIT
L_17:
MOV AL,Byte Ptr SUPSPC ;GET SPACE SUPPRESSION FLAG
OR AL,AL ;SEE IF PRINTING FILE TOTALS
JNZ L_18
RET ;YES, DON'T GIVE LEADING SPACES
L_18:
JMP SPACE ;LEADING ZERO...PRINT SPACE
DIGNZ: MOV Byte Ptr LZFLG,AL ;SET LEADING ZERO FLAG SO NEXT ZERO PRINTS
JMP SEND_CHAR ;AND PRINT DIGIT
;
; SHOW TOTAL SPACE AND FILES USED
;
PRTOTL: XOR AL,AL ;GET A ZERO TO...
MOV Byte Ptr SUPSPC,AL ;SUPPRESS LEADING SPACES IN TOTALS
MOV BX,Word Ptr TOTFIL ;HOW MANY FILES DID WE MATCH?
MOV AL,BH
OR AL,BL
JZ NXTUSR ;SKIP THE SUMMARY IF WE DIDN'T FIND ANY
PUSH BX ;SAVE TOTFIL
MOV Byte Ptr FNDFLG,AL ;SET FILE FOUND FLAG
MOV DX,(Offset TOTMS1) ;PRINT [CR,LF,LF]"DRIVE "
CALL PRINT
MOV AL,Byte Ptr .FCB
ADD AL,'A'-1
CALL SEND_CHAR ;OUTPUT THE DRIVE CODE
MOV DX,(Offset TOTMS2) ;PRINT ", USER "
CALL PRINT
CALL TYPUSR ;OUTPUT THE USER NUMBER
MOV DX,(Offset TOTMS3) ;PRINT " CONTAINS "
CALL PRINT
MOV BX,Word Ptr TOTSIZ ;PRINT TOTAL K USED BY FILES MATCHED
CALL DECPRT
MOV DX,(Offset TOTMS4) ;PRINT "K IN "
CALL PRINT
POP BX ;RECALL TOTFIL
CALL DECPRT ;PRINT NUMBER OF FILES MATCHED
MOV DX,(Offset TOTMS5) ;PRINT " FILES WITH "
CALL PRINT
CALL PRTFRE ;OUTPUT FREE SPACE REMAINING & " FREE."
;
; DIRECTORY FOR ONE USER AREA COMPLETED. IF ALL USERS OPTION IS
; SELECTED, THEN GO DO ANOTHER DIRECTORY ON THE NEXT USER NUMBER
; UNTIL WE EXCEED THE MAXIMUM USER # FOR THE SELECTED DRIVE.
;
IF AOPT
NXTUSR: ;IF ALL USERS OPTION ENABLED
MOV AL,Byte Ptr AOPFLG ;IF NOT ALL USERS MODE - SKIP NEXT
OR AL,AL
JNZ GOCLZ
CALL CKABRT ;CHECK FOR USER ABORT FIRST
MOV AL,Byte Ptr MAXUSR ;NO ABORT - GET MAXIMUM USER NUMBER
MOV BX,(Offset NEWUSR) ;BUMP DIRECTORY USER NUMBER
INC M
CMP AL,M ;DOES NEXT USER # EXCEED MAXIMUM?
JNAE L_19
JMP SETTBL ;CONTINUE IF MORE USER AREAS TO GO
L_19:
ENDIF
;
;IF MULTI-DISK OPTION ENABLED
IF AOPT AND DOPT
MOV AL,Byte Ptr BASUSR ;RESET BASE USER NUMBER FOR THE
MOV M,AL ;..NEXT DIRECTORY SEARCH
ENDIF
;
; WE'VE FINISHED ALL OF OUR OUTPUTTING. FLUSH THE REMAINDER OF THE
; OUTPUT BUFFER AND CLOSE THE FILE BEFORE GOING TO EXIT ROUTINE.
;
IF FOPT
GOCLZ:
MOV BX,(Offset OPNFLG) ;GET FILE OPEN STATUS THEN RESET FLAG TO
MOV AL,M ;..FORCE REOPEN ON NEXT PASS
MOV M,0
OR AL,AL
JZ NXTDSK ;SKIP CLOSING XDIR.DIR IF IT WASN'T OPENED
MOV BX,(Offset BUFCNT)
MOV AL,M ;RETRIEVE # OF UNFLUSHED CHARACTERS IN BUFFER
MOV M,128 ;FORCE BUFCNT TO EMPTY STATUS FOR NEXT DRIVE
OR AL,AL ;IF BUFCNT=128, BUFFER EMPTY SO SET SIGN BIT
JS CLOZE ;CLOSE XDIR.DIR IF BUFFER IS EMPTY
JZ FLUSH ;WRITE LAST RECORD TO XDIR.DIR IF BUFFER FULL
MOV BX,Word Ptr BUFPNT ;OTHERWISE, PAD UNUSED BUFFER WITH CTRL-ZS
PUTAGN: MOV M,'Z'-40H
LAHF
INC BX
SAHF
DEC AL
JNZ PUTAGN ;CONTINUE PADDING TIL BUFFER FILLED OUT
FLUSH: MOV DX,(Offset OUTFCB) ;FLUSH THE LAST OUTPUT BUFFER
MOV CL,WRITE
CALL CPM
OR AL,AL
JZ L_20
JMP WRTERR
L_20:
CLOZE: MOV DX,(Offset OUTFCB) ;CLOSE THE OUTPUT FILE
MOV CL,CLOSE
CALL CPM
ENDIF
;
; DIRECTORY FOR ALL USER AREAS COMPLETED. IF THE MULTI-DISK OPTION
; IS ENABLED AND SELECTED, RESET TO THE BASE USER AREA AND REPEAT
; THE DIRECTORY FOR NEXT DRIVE ON-LINE UNTIL WE EITHER EXCEED THE
; DRIVES IN OUR LODRV-HIDRV TABLE, OR THE BDOS SHUTS US DOWN WITH
; A SELECT OR BAD SECTOR ERROR, WHICH WILL BE INTERCEPTED BACK TO
; THE EXIT MODULE.
;
NXTDSK: MOV BX,(Offset FNDFLG) ;GET FILE FOUND FLAG
MOV AL,M
MOV M,0 ;CLEAR FILE FOUND FLAG FOR NEXT DRIVE
OR AL,AL
JNZ NDSK ;CONTINUE IF AT LEAST 1 FILE FOUND
;
;IF FILE OUTPUT ENABLED, DISABLE TEMPORARILY
;
IF FOPT
MOV BX,(Offset FOPFLG)
DEC M
PUSH BX
ENDIF
MOV AL,Byte Ptr .FCB ;STASH ASCII DIRECTORY DRIVE IN NO FILE MSG
ADD AL,'A'-1
MOV Byte Ptr NOFMS2,AL
MOV DX,(Offset NOFMS1) ;PRINT "NO FILE ON ? - "
CALL PRINT
CALL PRTFRE ;TAG WITH FREE MESSAGE
;
;RESTORE ORIGINAL FILE OUTPUT MODE
;
IF FOPT
POP BX
INC M
ENDIF
IF DOPT
NDSK: ;IF MULTI-DISK OPTION ENABLED
MOV AL,Byte Ptr DOPFLG ;IF MULTI-DISK NOT SELECTED - SKIP NEXT
OR AL,AL
JZ L_21
JMP EXIT
L_21:
CALL CKABRT ;CHECK FOR USER ABORT FIRST
MOV AL,(Offset HIDRV)-(Offset LODRV) ;GET MAXIMUM DRIVE CODE TO SEARCH
MOV BX,FCB ;BUMP DIRECTORY FCB DRIVE CODE
INC M
CMP AL,M ;DOES NEXT DISK EXCEED MAXIMUM?
JNAE L_22
JMP NOOPT ;SEARCH NEXT DISK IF NOT
L_22:
ENDIF
JMP EXIT ;ALL DONE - EXIT TO CCP
;
; PRINT THE USER NUMBER OF THE DIRECTORY IN DECIMAL
;
TYPUSR:
MOV AL,Byte Ptr NEWUSR
CMP AL,10 ;IF USER NO. > 9 PRINT LEADING 1
JB DUX
MOV AL,'1'
CALL SEND_CHAR
MOV AL,Byte Ptr NEWUSR ;PRINT LOW DIGIT OF USER NO.
SUB AL,10
DUX: ADD AL,'0'
JMPS SEND_CHAR
;
; FORCE NEW LINE ON VIDEO AND CHECK FOR PAGE PAUSE
;
CRLF: MOV AL,0DH ;SEND CR
CALL SEND_CHAR
MOV AL,0AH ;SEND LF
JMPS SEND_CHAR ;EXIT TO CALLER FROM TYPE
;
; SEPARATE THE DIRECTORY OUTPUT ON A LINE WITH A SPACE, THE DELIMITER,
; FOLLOWED BY ANOTHER SPACE.
;
FENCE: CALL SPACE
MOV AL,DELIM ;FENCE CHARACTER
FPAD: CALL SEND_CHAR ;PRINT IT, FALL INTO SPACE
SPACE: MOV AL,' ' ;FALL THROUGH TO TYPE
;
; OUTPUT CHARACTER IN A TO CONSOLE, AND OPTIONALLY TO PRINTER AND/OR
; THE OUTPUT FILE.
;
SEND_CHAR:
PUSH CX
PUSH DX
PUSH BX
IF FOPT OR POPT OR PGPAWZ
LAHF ;SAVE THE CHARACTER TO OUTPUT
XCHG AL,AH
PUSH AX
XCHG AL,AH
ENDIF
CALL TYPE1 ;SEND IT TO CONSOLE
IF FOPT OR POPT OR PGPAWZ
POP AX ;RESTORE THE OUTPUT CHARACTER
XCHG AL,AH
AND AL,7FH ;STRIP PARITY BIT ON CHARACTER
ENDIF
;
; TEST FILE OUTPUT MODE AND SKIP TO PAGE PAUSE TEST IF NOT ACTIVE.
;
IF FOPT
MOV CH,AL ;SAVE STRIPPED CHARACTER TO B
MOV AL,Byte Ptr FOPFLG ;IS FILE OUTPUT ACTIVE?
OR AL,AL
JNZ NOWRIT ;GO CHECK FOR PAGE PAUSE IF NOT
;
; FILE OUTPUT MODE ACTIVE - MAKE SURE WE HAVE ROOM IN BUFFER TO ADD
; NEXT CHARACTER. IF BUFFER FULL, WRITE OUT CURRENT RECORD FIRST
; AND THEN START A NEW RECORD WITH CURRENT CHARACTER.
;
MOV BX,Word Ptr BUFPNT ;GET CURRENT BUFFER POINTER
MOV AL,Byte Ptr BUFCNT ;GET BUFFER CAPACITY REMAINING
OR AL,AL
JNZ PUTBUF ;CONTINUE IF BUFFER NOT FULL
MOV DX,(Offset OUTFCB) ;OTHERWISE, WRITE THE CURRENT BUFFER OUT
MOV CL,WRITE
CALL CPM ;(NOTE CALL MUST SAVE CHARACTER IN B)
OR AL,AL
JZ L_23
JMP WRTERR ;TAKE WRITE ERROR EXIT IF DISK FULL OR R/O
L_23:
MOV BX,(Offset OUTBUF) ;RESET BUFFER POINTER
MOV AL,128 ;RESET BUFFER CAPACITY
PUTBUF: MOV M,CH ;SHOVE CHARACTER TO NEXT BUFFER POSITION
INC BX ;BUMP BUFFER POINTER
MOV Word Ptr BUFPNT,BX ;.. AND SAVE IT
DEC AL ;DOCK COUNT OF CHARACTERS LEFT IN BUFFER
MOV Byte Ptr BUFCNT,AL ;..AND SAVE IT
NOWRIT: MOV AL,CH ;RECALL STRIPPED CHARACTER
ENDIF
;
;IF PRINTER OPTION
;
IF POPT
MOV DL,AL ;SETUP LIST OUTPUT CALL
MOV CL,5
MOV AL,Byte Ptr POPFLG ;TEST PRINTER FLAG
OR AL,AL
JNZ L_24
CALL CPM ;PRINT CHARACTER IF FLAG TRUE
L_24:
MOV AL,DL ;RECALL CHARACTER
ENDIF
IF PGPAWZ
CMP AL,0AH ;DO WE HAVE A LF?
JNZ TYPRET ;EXIT IF NOT
ENDIF
IF NOPT AND PGPAWZ
MOV AL,Byte Ptr NOPFLG ;IS THE PAGE PAUSE FUNCTION DISABLED?
OR AL,AL
JZ TYPRET ;EXIT IF SO
ENDIF
IF PGPAWZ
MOV AL,Byte Ptr LINCNT ;GET LINE COUNT
INC AL ;BUMP IT
CMP AL,LPS ;ARE WE AT THE END OF THE SCREEN?
JB NOTEOS ;SKIP IF NOT
MOV DX,(Offset EOSMSG) ;ELSE, DISPLAY PAUSE MESSAGE
MOV CL,9 ;..WITHOUT CHECKING FOR LFS
INT 224
CALL CINPUT ;WAIT FOR CHARACTER
CMP AL,'C'-40H
JNZ L_25
JMP EXIT ;ABORT ON CTRL-C
L_25:
XOR AL,AL ;RESET LINE COUNT
NOTEOS: MOV Byte Ptr LINCNT,AL ;SAVE NEW LINE COUNT
ENDIF
TYPRET: POP BX ;EXIT FROM TYPE
POP DX
POP CX
RET
;
; OUTPUT CHARACTER
;
TYPE1: MOV DL,AL ;GET CHARACTER INTO BDOS ENTRY REGISTER
MOV CL,WRCHR
INT 224 ;CALL CONOUT VIA THE BDOS
RET
;
; PRINT A STRING AT HL OF LENGTH B
;
TYPEIT: MOV AL,M
CALL SEND_CHAR
LAHF
INC BX
SAHF
DEC CH
JNZ TYPEIT
RET
;
; PRINT STRING TERMINATED WITH LAST BYTE HIGH ON CONSOLE.
;
PRINT: MOV SI,DX
MOV AL,[SI]
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
AND AL,7FH
CALL SEND_CHAR
POP AX
XCHG AL,AH
OR AL,AL
JNS L_26
RET
L_26:
LAHF
INC DX
SAHF
JMPS PRINT
;
; FETCH CHARACTER FROM CONSOLE (WITHOUT ECHO)
;
CINPUT: MOV Byte Ptr FUNC,3 ;bios console input function
MOV Word Ptr BIOS_DESC,CX ;pass disk number to bios descriptor
MOV Word Ptr BIOS_DESC+2,0 ;fill remaining descriptor (DX) zero
MOV DX,(Offset FUNC) ;point to function parameter block
MOV CL,50 ;direct bios call
INT 224 ;do it, to it...
AND AL,7FH
RET
;
; CHECK FOR A CTRL-C OR CTRL-S ENTERED FROM THE KEYBOARD. JUMP TO
; EXIT IF CTRL-C, PAUSE ON CTRL-S.
;
CKABRT: MOV Byte Ptr FUNC,2 ;bios console status function
MOV Word Ptr BIOS_DESC,CX ;pass disk number to bios descriptor
MOV Word Ptr BIOS_DESC+2,0 ;fill remaining descriptor (DX) zero
MOV DX,(Offset FUNC) ;point to function parameter block
MOV CL,50 ;direct bios call
INT 224 ;do it, to it...
OR AL,AL
JNZ L_27
RET ;NO, RETURN TO CALLER
L_27:
CALL CINPUT ;GET CHARACTER
CMP AL,'C'-40H ;CTRL-C?
JNZ L_28
JMP EXIT ;IF CTRL-C THEN QUIT
L_28:
CMP AL,'S'-40H ;CTRL-S?
JZ L_29
RET ;NO, RETURN TO CALLER
L_29:
CALL CINPUT ;YES, WAIT FOR ANOTHER CHAR.
CMP AL,'C'-40H ;MIGHT BE CTRL-C
JNZ L_30
JMP EXIT ;EXIT IF CTRL-C, ELSE FALL THRU AND CONTINUE
L_30:
RET
;
; ENTRY TO BDOS SAVING ALL EXTENDED REGISTERS
;
CPM: PUSH CX
PUSH DX
PUSH BX
INT 224
POP BX
POP DX
POP CX
RET
;
; FOR FILE OUTPUT MODE, RETURN TO OLD USER AREA AND SET DMA FOR
; THE FILE OUTPUT BUFFER.
;
IF UOPT OR AOPT
SETFOP:
MOV AL,Byte Ptr OLDUSR ;GET USER NUMBER AT STARTUP
MOV DL,AL
MOV CL,CURUSR
CALL CPM ;RESET THE OLD USER NUMBER IF CP/M 2
ENDIF
IF FOPT
MOV DX,(Offset OUTBUF) ;MOVE DMA FROM SEARCH BUFFER INTO THE
JMPS SET2 ;..OUTPUT BUFFER
ENDIF
RET
;
; MOVE DISK BUFFER DMA TO DEFAULT BUFFER FOR DIRECTORY SEARCH OPERATIONS
; AND BDOS MEDIA CHANGE ROUTINES.
;
SETSRC: MOV DX,BASE+80H
SET2: MOV CL,SETDMA
JMPS CPM
;
; PRINT THE AMOUNT OF FREE SPACE REMAINING ON THE SELECTED DRIVE
;
PRTFRE: MOV BX,Word Ptr FREEBY ;GET SPACE LEFT BEFORE ADDING TO MASTER.DIR
CALL DECPRT ;PRINT K FREE
MOV DX,(Offset TOTMS6) ;PRINT " FREE."
JMP PRINT
;
; COMPARE ROUTINE FOR SORT
;
COMPR: PUSH BX ;SAVE TABLE ADDR
MOV DL,M ;LOAD LOW ORDER
INC BX
MOV DH,M ;LOAD HIGH ORDER
INC BX
MOV CL,M
INC BX
MOV CH,M
;
; BC, DE NOW POINT TO ENTRIES TO BE COMPARED
;
XCHG BX,DX
MOV DL,AL ;GET COUNT
CMPLP: MOV SI,CX
MOV AL,[SI]
CMP AL,M
LAHF
INC BX
SAHF
LAHF
INC CX
SAHF
JNZ NOTEQL ;QUIT ON MISMATCH
DEC DL ;OR END OF COUNT
JNZ CMPLP
NOTEQL: POP BX
RET ;COND CODE TELLS ALL
;
; SWAP ENTRIES IN THE ORDER TABLE
;
SWAP: MOV CX,(Offset ORDER)-2 ;TABLE BASE
SHL BX,1 ;*2
LAHF ;+ BASE
ADD BX,CX
SAHF
XCHG BX,DX
SHL BX,1 ;*2
LAHF ;+ BASE
ADD BX,CX
RCR SI,1
SAHF
RCL SI,1
MOV CL,M
MOV SI,DX
MOV AL,[SI]
XCHG BX,DX
MOV M,CL
MOV SI,DX
MOV [SI],AL
LAHF
INC BX
SAHF
LAHF
INC DX
SAHF
MOV CL,M
MOV SI,DX
MOV AL,[SI]
XCHG BX,DX
MOV M,CL
MOV SI,DX
MOV [SI],AL
RET
;
; NEW COMPARE ROUTINE
;
COMPARE:MOV CX,(Offset ORDER)-2
SHL BX,1
ADD BX,CX
XCHG BX,DX
SHL BX,1
ADD BX,CX
XCHG BX,DX
MOV CL,M
INC BX
MOV CH,M
XCHG BX,DX
MOV DL,M
INC BX
MOV DH,M
XCHG BX,DX
MOV DL,AL ;COUNT
CMPLPE: MOV SI,CX
MOV AL,[SI]
CMP AL,M
LAHF
INC CX
SAHF
LAHF
INC BX
SAHF
JZ L_31
RET
L_31:
DEC DL
JNZ CMPLPE
RET
;
; ERROR EXIT
;
IF FOPT
ERXIT:
MOV AL,0FFH
MOV Byte Ptr FOPFLG,AL ;DISABLE FILE OUTPUT MODE ON ERROR
ENDIF
CALL CRLF ;SPACE DOWN
POP DX ;GET POINTER TO MESSAGE STRING
CALL PRINT ;PRINT IT
MOV DX,(Offset ERRMS1) ;PRINT " ERROR"
CALL PRINT
CALL CRLF ;SPACE DOWN
;
; EXIT - ALL DONE, RESTORE STACK
;
EXIT: MOV CL,CONST ;CHECK CONSOLE STATUS
CALL CPM
OR AL,AL ;CHAR WAITING?
MOV CL,RDCHR
JZ L_32
CALL CPM ;GOBBLE UP CHAR
L_32:
MOV AL,Byte Ptr ROPFLG ;IF DISK SYSTEM WAS RESET
OR AL,AL
MOV AL,Byte Ptr OLDDSK ;GET DEFAULT DISK AT STARTUP
MOV DL,AL
MOV CL,SELDSK ;RESELECT IT
JNZ L_33
CALL CPM
L_33:
;
MOV CL,0 ;BDOS FUNCTION, WARM BOOT
MOV DL,0
INT 224 ;RETURN TO CP/M-86
;
; END OF PROGRAM CODE
;
; INITIALIZED DATA AREA
;
DREMSG DB 'Driv','e' OR 80H
;
IF PGPAWZ
EOSMSG DB 0AH,'Press any key to continue, or CTRL-C to exit',0DH,0AH,0AH,'$'
ENDIF
;
ERRMS1 DB ' '
;
ERRMS2 DB 'Erro','r' OR 80H
;
IF REPERR
ERRTAG DB ' -','>' OR 80H
ENDIF
;
NOFMS1 DB 0DH,0AH,'No such file on Drive '
;
NOFMS2 DB ' -',' ' OR 80H
;
TOTMS1 DB 0DH,0AH,0DH,0AH,'Drive',' ' OR 80H
;
TOTMS2 DB ', User',' ' OR 80H
;
TOTMS3 DB ' contains',' ' OR 80H
;
TOTMS4 DB 'K in',' ' OR 80H
;
TOTMS5 DB ' files with',' ' OR 80H
;
TOTMS6 DB 'K free',0DH,0AH OR 80H
;
USRMSG DB 'User ','#' OR 80H
;
FNDFLG DB 0 ;FLAG WHETHER ANY FILES MATCHED
;
IF PGPAWZ
LINCNT DB 0 ;COUNT OF LINES PRINTED ON SCREEN
ENDIF
;
; DRIVE CODE/USER AREA LOOKUP TABLE
; NOTE THAT THE LODRV-HIDRV TABLE IS INCLUDED HERE FULLY CONFIGURED.
; FOR YOUR OWN USE, YOU SHOULD CHANGE THE MAXIMUM USER AREAS AS
; APPROPRIATE FOR EACH DRIVE ON YOUR SYSTEM, AND THEN DELETE ANY
; DBS REFERENCING DRIVES THAT DON'T EXIST.
;
LODRV EQU (Offset $) ;MARK BEGINNING OF DRIVE/USER TABLE
DB 15 ;MAXIMUM USER AREA FOR DRIVE A
DB 15 ; " " " " " B
DB 15 ; " " " " " C
DB 15 ; " " " " " D
DB 15 ; " " " " " E
DB 15 ; " " " " " F
DB 15 ; " " " " " G
DB 15 ; " " " " " H
; DB 15 ; " " " " " I
; DB 15 ; " " " " " J
; DB 15 ; " " " " " K
; DB 15 ; " " " " " L
; DB 15 ; " " " " " M
; DB 15 ; " " " " " N
; DB 15 ; " " " " " O
; DB 15 ; " " " " " P
;
HIDRV EQU (Offset $) ;MARK END OF DRIVE/USER TABLE
;
; OPTION FIELD LOOKUP TABLE.
; NOTE THAT YOU CAN FORCE ANY OF THESE OPTIONS AS A DEFAULT BY
; CHANGING THE LETTER FOR THE OPTION INTO A ZERO (ASSUMING THAT
; ITS ENABLING EQUATE IS TRUE). EACH OPTION THAT YOU HARD-WIRE IN
; THIS MANNER WILL NO LONGER BE RECOGNIZED AS A COMMAND LINE OPTION,
; AND IF YOU REDUNDANTLY KEY IT IN, XDIR WILL FLAG IT AS UNRECOGNIZED.
;
OTBL EQU (Offset $) ;MARK START OF OPTION TABLE
;
;ALL USERS-OPTION FLAG
;
IF AOPT
AOPFLG DB 'A'
ENDIF
;
;MULTI-DISK-OPTION FLAG
;
IF DOPT
DOPFLG DB 'D'
ENDIF
;
;FILE-OUTPUT-OPTION FLAG
;
IF FOPT
FOPFLG DB 'F'
ENDIF
;
;NO PAGE-PAUSE OPTION FLAG
;
IF NOPT AND PGPAWZ
NOPFLG DB 'N'
ENDIF
;
;PRINTER OPTION FLAG
;
IF POPT
POPFLG DB 'P'
ENDIF
;
;RESET OPTION FLAG
;
ROPFLG DB 'R'
;
;SYSTEM FILE OPTION FLAG
;
IF SOPT
SOPFLG DB 'S'
;
ENDIF
OEND EQU (Offset $) ;MARK END OF OPTION TABLE
;
; END OF OPTION LOOKUP TABLE
;
IF FOPT
BUFPNT DW (Offset OUTBUF) ;POINTER TO NEXT LOCATION IN OUTPUT BUFFER
BUFCNT DB 128 ;NUMBER OF BYTES LEFT IN OUTPUT BUFFER
OPNFLG DB 0 ;FILE OPEN FLAG FOR ALL USER FILE OUTPUT
;
OUTFCB DB 0,'XDIR DIR'
DB 0 ;REST OF XDIR.DIR FILE CONTROL BLOCK
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
DB 0
;
OUTBUF RS 128 ;OUTPUT FILE BUFFER
ENDIF
;
; UNINITIALIZED DATA AREA
;
;storage for 5 byte BIOS function descriptor
;
FUNC RS 1 ;bios function code goes here
BIOS_DESC RS 2 ;[CX] data goes here
RS 2 ;[DX] data goes here
;
BASUSR RS 1 ;DUPE OF ORIGINAL DIRECTORY USER # TO SEARCH
BLKMAX RS 2 ;HIGHEST BLOCK # ON DRIVE
BLKMSK RS 1 ;SEC/BLK - 1
BLKSHF RS 1 ;# SHIFTS TO MULT BY SEC/BLK
COUNT RS 2 ;ENTRY COUNT
dsksiz RS 2 ;HIGHEST FILE # IN DIRECTORY
FREEBY RS 2 ;CONTAINS NUMBER OF K LEFT ON DIRECTORY DRIVE
GAP RS 2 ;SORT ROUTINE STORAGE
I RS 2 ;SORT ROUTINE STORAGE
J RS 2 ;SORT ROUTINE STORAGE
JGAP RS 2 ;SORT ROUTINE STORAGE
LZFLG RS 1 ;0 WHEN PRINTING LEADING ZEROS
MAXUSR RS 1 ;MAXIMUM USER # FOR DRIVE FROM LOOKUP TABLE
NEWUSR RS 1 ;CONTAINS USER NUMBER SELECTED BY "$U" OPTION
NEXTT RS 2 ;NEXT TABLE ENTRY
OLDDSK RS 1 ;HOLDER FOR CURRENTLY LOGGED-IN DRIVE
OLDUSR RS 1 ;CONTAINS USER NUMBER UPON INVOCATION
SCOUNT RS 2 ;# TO SORT
SUPSPC RS 1 ;LEADING SPACE FLAG FOR DECIMAL ROUTINE
TBLOC RS 2 ;POINTER TO START OF NAME TABLE
TEMP RS 2 ;SAVE DIR ENTRY
TOTFIL RS 2 ;TOTAL NUMBER OF FILES
TOTSIZ RS 2 ;TOTAL SIZE OF ALL FILES
ORDER EQU (Offset $) ;ORDER TABLE STARTS HERE
;
RS 4000H
DB 0
;
END