MS-DOS/v2.0/source/CHKDSK.ASM

901 lines
26 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

TITLE CHKDSK - MS-DOS Disk consistancy checker
; CHKDSK Version 2.30
; Verifies and repairs MS-DOS disk directory.
; To build CHKDSK you need three modules:
; CHKDSK CHKPROC CHKMES
; They should be linked the that order as well.
; REVISION HISTORY
;REV 1.1
; 05/21/82 Added rev number
;REV 1.5
; Mod by NANCYP to report on extents
; Mod by AARONR to report volume ID
;REV 2.0
; Total rewrite for directories
;REV 2.1
; Added ^C and INT 24H handlers
;REV 2.2
; INTERNATIONAL support
;REV 2.3
; Split into two modules to allow assembly on a PC
; CHKDSK and CHKPROC
FALSE EQU 0
TRUE EQU NOT FALSE
DRVCHAR EQU ":"
;The following defines the ranges of DOS version numbers for which this CHKDSK
; is good
DOSVER_LOW EQU 0136H ;1.54 in hex
DOSVER_HIGH EQU 020BH ;2.11 in hex
INCLUDE DOSSYM.ASM
FCB EQU 5CH
;Drive parameter block from DOS header
SUBTTL Segments used in load order
CODE SEGMENT PUBLIC
CODE ENDS
CONST SEGMENT PUBLIC BYTE
CONST ENDS
DATA SEGMENT PUBLIC WORD
DATA ENDS
DG GROUP CODE,CONST,DATA
SUBTTL Initialized Data
PAGE
CONST SEGMENT PUBLIC BYTE
PUBLIC HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX
PUBLIC HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS
PUBLIC DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS
PUBLIC DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV
PUBLIC FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR
EXTRN IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE
EXTRN TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE
EXTRN CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE
EXTRN BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE
EXTRN CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE
EXTRN BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE
DIRBUF LABEL BYTE ;Entry buffer for searches
VOLID DB -1,0,0,0,0,0,8 ;Volume ID FCB
VOLNAM DB 0,"???????????"
DB 25 DUP(0)
ALLFILE DB -1,0,0,0,0,0,1EH ;Extended FCB
ALLDRV DB 0,"???????????"
DB 25 DUP (?)
ORPHFCB DB 0,"FILE0000"
ORPHEXT DB "CHK"
DB 25 DUP (?)
;Non-message data
SWITCHAR DB "-"
ROOTSTR LABEL BYTE
DIRCHAR DB "/"
NUL DB 0
PARSTR DB "..",0
DOTMES DB ".",0
DOTENT DB ". "
DDOTENT DB ".. "
HECODE DB ?
FIXMFLG DB 0 ;Flag for printing fixmes
ERRSUB DW 0 ;Flag for bad subdir error
FRAGMENT DB 0 ;Flag for extent processing
DIRTYFAT DB 0 ;Dirty flag for FAT
DIRCNT DW 0 ;# directories
DIRSIZ DW 0 ;# alloc units in directories
FILCNT DW 0 ;# reg files
FILSIZ DW 0 ;# alloc units in reg files
HIDCNT DW 0 ;# hidden files
HIDSIZ DW 0 ;# alloc units in hidden files
BADSIZ DW 0 ;# alloc units in bad sectors
ORPHCNT DW 0 ;# orphan files made
ORPHSIZ DW 0 ;# alloc units in orphan files
LCLUS DW 0 ;# alloc units in lost clusters
DISPFLG DB 0 ;used by number routines
CROSSCNT DW 0 ;# crosslinked files (first pass)
SECONDPASS DB 0 ;Pass flag
HAVFIX DB 0 ;non zero if any fixes
DOFIX DB 0 ;flag for F switch
NOISY DB 0 ;flag for V switch
USERDIR DB "/",0 ;Users current dir for drive
DB (DIRSTRLEN-1) DUP (?)
CONBUF DB 15,0 ;Input buffer
DB 15 DUP (?)
CONST ENDS
SUBTTL Un-initialized Data
PAGE
DATA SEGMENT PUBLIC WORD
PUBLIC ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT
PUBLIC SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP
PUBLIC HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD
HARDCH DD ? ;Pointer to real INT 24 handler
CONTCH DD ? ;Pointer to real INT 23 handler
THISDPB DD ? ;Pointer to drive DPB
USERDEV DB ? ;Users current device
CSIZE DB ? ;Sectors per cluster
SSIZE DW ? ;bytes per sector
DSIZE DW ? ;# alloc units on disk
MCLUS DW ? ;DSIZE + 1
NAMBUF DB 14 DUP (?) ;Buffer
DOTSNOGOOD DB ? ;. or .. error flag
ZEROTRUNC DB ? ;Trimming flag
ISCROSS DB ? ;Crosslink flag
OLDCLUS DW ?
SRFCBPT DW ?
FATMAP DW OFFSET DG:FAT ;Offset of FATMAP table
SECBUF DW ? ;Offset of sector buffer
ERRCNT DB ? ;Used by FATread and write
STACKLIM DW ? ;Stack growth limit
INTERNATVARS internat_block <>
DB (internat_block_max - ($ - INTERNATVARS)) DUP (?)
FAT LABEL WORD
DATA ENDS
SUBTTL Start of CHKDSK
CODE SEGMENT PUBLIC
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
PUBLIC SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT
PUBLIC PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES
EXTRN RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR
EXTRN PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR
EXTRN INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR
EXTRN FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR
ORG 100H
CHKDSK:
JMP SHORT CHSTRT
HEADER DB "Ver 2.30"
CHSTRT:
;Code to print header.
; PUSH AX
; MOV DX,OFFSET DG:HEADER
; CALL PRINT
; POP AX
PUSH AX ;Save DRIVE validity info
MOV AH,GET_VERSION
INT 21H
XCHG AH,AL ;Turn it around to AH.AL
CMP AX,DOSVER_LOW
JB GOTBADDOS
CMP AX,DOSVER_HIGH
JBE OKDOS
GOTBADDOS:
MOV DX,OFFSET DG:BADVER
JMP CERROR
OKDOS:
POP AX ;Get back drive info
MOV BX,0FFF0H
MOV DX,SP
CMP DX,BX
JAE STACKOK ;Lots of stack
MOV DX,DS:[2] ;High break
MOV CX,CS
SUB DX,CX
CMP DX,0FFFH
JAE SETSTACK ;Lots to grab
MOV CX,4 ;Suck up more stack (blast command)
SHL DX,CL
MOV BX,DX
SETSTACK:
CLI
MOV SP,BX
STI
STACKOK:
PUSH AX
MOV AH,DISK_RESET ;Flush everything, and invalidate
INT 21H
POP AX
CMP AL,0FFH ;Illegal drive specifier?
JNZ FILECHK ;No -- check for filename
DRVERR:
MOV DX,OFFSET DG:BADDRV
CERROR:
PUSH CS ;Make sure DS is OK
POP DS
CALL PRINT ;Print error message
INT 20H
CERROR2:
PUSH DX
CALL DONE ;Reset users disk
POP DX
JMP SHORT CERROR
FILECHK:
MOV AX,(CHAR_OPER SHL 8)
INT 21H
MOV [SWITCHAR],DL
CMP DL,"/"
JNZ SLASHOK
MOV [DIRCHAR],"\"
MOV [USERDIR],"\"
SLASHOK:
CMP DS:(BYTE PTR FCB+1)," " ;Filename specified?
JZ DRVCHK ;No -- get the correct drive
MOV AL,[SWITCHAR]
CMP DS:(BYTE PTR FCB+1),AL ;Filename specified?
JZ DRVCHK ;No -- get the correct drive
MOV BYTE PTR [FRAGMENT],1 ;Set flag to perform fragment
;check on specified files
DRVCHK:
CALL SETSWITCH ;Look for switches
MOV AH,GET_DEFAULT_DRIVE ;Get current drive
INT 21H
MOV [USERDEV],AL ;Save for later
MOV AH,AL
INC AH ;A = 1
MOV BH,DS:(BYTE PTR FCB) ;See if drive specified
OR BH,BH
JZ SETDSK
MOV AL,BH
MOV AH,AL
DEC AL ;A = 0
SETDSK:
MOV [ALLDRV],AH ;Target drive
MOV [VOLNAM],AH ;A = 1
MOV [ORPHFCB],AH ;A = 1
ADD [BADDRVM],AL ;A = 0
ADD [BADDRVM2],AL ;A = 0
MOV DL,AH ;A = 1
MOV AH,GET_DPB ;Get the DPB
INT 21H
ASSUME DS:NOTHING
CMP AL,-1
JNZ DRVISOK ;Bad drive (should always be ok)
MOV DX,OFFSET DG:BADDRV
CERROR2J: JMP CERROR2
DRVISOK:
DEC DL ;A = 0
MOV AH,SET_DEFAULT_DRIVE ;Set Target
INT 21H
CMP [BX.dpb_current_dir],0
JZ CURRISROOT ;Save users current dir for target
MOV SI,BX
ADD SI,dpb_dir_text
MOV DI,OFFSET DG:USERDIR + 1
SETDIRLP:
LODSB
STOSB
OR AL,AL
JZ CURRISROOT
JMP SHORT SETDIRLP
CURRISROOT:
MOV WORD PTR [THISDPB+2],DS
PUSH CS
POP DS
ASSUME DS:DG
MOV WORD PTR [THISDPB],BX
MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 23H
INT 21H
MOV WORD PTR [CONTCH],BX
MOV WORD PTR [CONTCH+2],ES
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H
MOV DX,OFFSET DG:INT_23
INT 21H
MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H
INT 21H
MOV WORD PTR [HARDCH],BX
MOV WORD PTR [HARDCH+2],ES
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H
MOV DX,OFFSET DG:INT_24
INT 21H
PUSH CS
POP ES
MOV DX,OFFSET DG:ROOTSTR
MOV AH,CHDIR ;Start at root
INT 21H
MOV DX,OFFSET DG:BADCD
JC CERROR2J ;Couldn't get there
MOV DX,OFFSET DG:FAT ;Scratch space
MOV AH,SET_DMA
INT 21H
MOV DX,OFFSET DG:VOLID ;Look for VOL ID
MOV AH,DIR_SEARCH_FIRST
INT 21H
CMP AL,-1
JZ NOTVOLID
CALL PRINTID ;Have a VOL ID
NOTVOLID:
LDS BX,[THISDPB]
ASSUME DS:NOTHING
MOV AX,[BX.dpb_sector_size]
MOV [SSIZE],AX ;Sector size in bytes
MOV AL,[BX.dpb_cluster_mask]
INC AL
MOV [CSIZE],AL ;Sectros per cluster
MOV AX,[BX.dpb_max_cluster]
MOV [MCLUS],AX ;Bound for FAT searching
DEC AX
MOV [DSIZE],AX ;Total data clusters on disk
MOV AL,[BX.dpb_FAT_size] ;Sectors for one fat
XOR AH,AH
MOV CX,AX
MUL [SSIZE] ;Bytes for FAT
ADD [FATMAP],AX ;Allocate FAT space
MOV AX,[FATMAP]
ADD AX,[MCLUS]
ADD AX,2 ;Insurance
MOV [SECBUF],AX ;Allocate FATMAP space
ADD AX,[SSIZE]
ADD AX,20 ;Insurance
MOV [STACKLIM],AX ;Limit on recursion
MOV DI,CX
MOV CL,[BX.dpb_FAT_count] ;Number of FATs
MOV DX,[BX.dpb_first_FAT] ;First sector of FAT
PUSH CS
POP DS
ASSUME DS:DG
MOV BX,OFFSET DG:FAT
MOV AL,[ALLDRV]
DEC AL
MOV AH,'1'
RDLOOP:
XCHG CX,DI
PUSH DX
PUSH CX
PUSH DI
PUSH AX
INT 25H ;Read in the FAT
MOV [HECODE],AL
POP AX ;Flags
JNC RDOK
MOV DX,OFFSET DG:BADREAD_PRE ;Barfed
CALL PRINT
POP AX
PUSH AX
MOV DL,AH
CALL PRTCHR
MOV DX,OFFSET DG:BADREAD_POST
CALL PRINT
POP AX
POP CX
POP DI
POP DX
INC AH
ADD DX,DI
LOOP RDLOOP ;Try next FAT
CALL RDSKERR
JNZ NORETRY1
JMP NOTVOLID
NORETRY1:
MOV BX,OFFSET DG:BADRDMES
JMP FATAL ;Couldn't read any FAT, BARF
RDOK:
POP AX ;Clean up
POP AX
POP AX
POP AX
MOV SI,OFFSET DG:FAT
LODSB ;Check FAT ID byte
CMP AL,0F8H
JAE IDOK
MOV DX,OFFSET DG:BADIDBYT ;FAT ID bad
CALL PROMPTYN ;Ask user
JZ IDOK
JMP ALLDONE ;User said stop
IDOK:
MOV DI,[FATMAP]
MOV CX,[MCLUS]
INC CX
XOR AL,AL
REP STOSB ;Initialize FATMAP to all free
MOV DX,OFFSET DG:DIRBUF ;FOR ALL SEARCHING
MOV AH,SET_DMA
INT 21H
XOR AX,AX
PUSH AX ;I am root
PUSH AX ;Parent is root
CALL DIRPROC
CALL CHKMAP ;Look for badsectors, orphans
CALL CHKCROSS ;Check for second pass
CALL DOCRLF
CALL REPORT
ALLDONE:
CALL AMDONE
INT 20H ;Fini
ASSUME DS:DG
SUBTTL Check for extents in specified files
PAGE
CHECKFILES:
;Search the directory for the files specified on the command line
;and report the number of fragmented allocation units found in
;each one.
CALL DOCRLF
MOV AH,SET_DMA
MOV DX,[FATMAP] ;Use the first free space available
MOV BP,DX
ADD BP,27 ;cluster in the directory entry
INT 21H
MOV AH,DIR_SEARCH_FIRST ;Look for the first file
FRAGCHK:
MOV DX,FCB
INT 21H
OR AL,AL ;Did we find it?
JNZ MSGCHK ;No -- we're done
XOR AX,AX ;Initialize the fragment counter
MOV SI,[BP] ;Get the first cluster
CALL UNPACK
CMP DI,0FF8H ;End-of-file?
JAE NXTCHK ;Yes -- go report the results
INC SI
CMP SI,DI
JZ EACHCLUS
INC AX
EACHCLUS:
MOV [OLDCLUS],DI ;Save the last cluster found
MOV SI,DI ;Get the next cluster
CALL UNPACK
INC [OLDCLUS] ;Bump the old cluster
CMP DI,[OLDCLUS] ;Are they the same?
JNZ LASTCLUS ;No -- check for end-of-file
JMP SHORT EACHCLUS ;Continue processing
LASTCLUS:
CMP DI,0FF8H ;End-of-file?
JAE NXTCHK ;Yes -- go report the results
INC AX ;No -- found a fragement
JMP SHORT EACHCLUS ;Continue processing
NXTCHK:
OR AX,AX
JZ GETNXT
MOV [FRAGMENT],2 ;Signal that we output at least one file
PUSH AX ;Save count of fragments
MOV SI,[FATMAP]
INC SI
CALL PRINTTHISEL2
CALL DOCRLF
MOV DX,OFFSET DG:CONTAINS ;Print message
CALL PRINT
POP SI ;Number of fragments found
INC SI ;Number non-contig blocks
XOR DI,DI
MOV BX,OFFSET DG:EXTENTS
PUSH BP
CALL DISP16BITS
POP BP
GETNXT:
MOV AH,DIR_SEARCH_NEXT ;Look for the next file
JMP FRAGCHK
MSGCHK:
CMP AH,DIR_SEARCH_FIRST
JNZ FILSPOK
MOV SI,FCB + 1 ;File not found error
CALL PRINTTHISEL2
CALL DOCRLF
MOV DX,OFFSET DG:OPNERR
CALL PRINT ;Bad file spec
RET
FILSPOK:
CMP BYTE PTR [FRAGMENT],2
JZ CDONE
MOV DX,OFFSET DG:NOEXTENTS
CALL PRINT
CDONE:
RET
FIGREC:
;Convert cluster number in BX to sector # AH of cluster in DX
LDS DI,[THISDPB]
ASSUME DS:NOTHING
MOV CL,[DI.dpb_cluster_shift]
MOV DX,BX
DEC DX
DEC DX
SHL DX,CL
OR DL,AH
ADD DX,[DI.dpb_first_sector]
PUSH CS
POP DS
ASSUME DS:DG
RET
SUBTTL PRINTID - Print Volume ID info
PAGE
PRINTID:
ASSUME DS:DG
MOV DX,OFFSET DG:INTERNATVARS
MOV AX,INTERNATIONAL SHL 8
INT 21H
MOV [DISPFLG],1 ;Don't sub spaces for leading zeros
MOV SI,OFFSET DG:FAT + 8
MOV DI,OFFSET DG:VNAME
MOV CX,11
REP MOVSB
MOV DX,OFFSET DG:IDMES1
CALL PRINT ;Print ID message
ADD SI,13
LODSW ;Get date
PUSH SI
MOV DX,AX
MOV AX,[INTERNATVARS.Date_tim_format]
OR AX,AX
JZ USPDAT
DEC AX
JZ EUPDAT
CALL P_YR
CALL P_DSEP
CALL P_MON
CALL P_DSEP
MOV CX,1000H ;Do not supress leading zeroes
CALL P_DAY
JMP P_TIME
USPDAT:
CALL P_MONTH_NAM
MOV CX,1110H ;Supress at most 1 leading 0
CALL P_DAY
PUSH DX
MOV DL,','
CALL PRTCHR
MOV DL,' '
CALL PRTCHR
POP DX
PYA:
CALL P_YR
JMP P_TIME
EUPDAT:
MOV CX,1110H ;Supress at most 1 leading 0
CALL P_DAY
PUSH DX
MOV DL,' '
CALL PRTCHR
POP DX
CALL P_MONTH_NAM
JMP PYA
P_DSEP:
PUSH DX
MOV DL,[INTERNATVARS.Date_sep]
CALL PRTCHR
POP DX
RET
P_MONTH_NAM:
MOV AX,DX
PUSH DX
MOV CL,5
SHR AX,CL
AND AX,0FH ;Month in AX
DEC AX ;Make 0 indexed
MOV CX,AX
SHL AX,1
ADD AX,CX ;Mult by 3 chars/mo
MOV SI,OFFSET DG:MONTAB
ADD SI,AX
LODSB
MOV DL,AL
CALL PRTCHR
LODSB
MOV DL,AL
CALL PRTCHR
LODSB
MOV DL,AL
CALL PRTCHR
MOV DL,' '
CALL PRTCHR
POP DX
RET
P_MON:
MOV SI,DX
PUSH DX
MOV CL,5
SHR SI,CL
AND SI,0FH ;Month in SI
CALL CONVERT
MOV DL,AL
MOV CX,1000H ;Do not supress leading 0
CALL OUTBYTE ;Print month
POP DX
RET
P_DAY:
MOV SI,DX
PUSH DX
PUSH CX
AND SI,01FH ;SI has day
CALL CONVERT
POP CX
MOV DL,AL
CALL OUTBYTE ;Print day
POP DX
RET
P_YR:
MOV SI,DX
PUSH DX
MOV CL,9
SHR SI,CL
AND SI,07FH ;SI has raw year
ADD SI,1980 ;Real year
CALL CONVERT
MOV CX,1000H ;Do not supress leading zeros
CALL OUTWORD ;Print year
POP DX
RET
P_TIME:
MOV DL,' '
CALL PRTCHR
POP SI
ADD SI,-4
LODSW ;Get time
MOV DI,AX
MOV SI,DI
MOV CL,11
SHR SI,CL
AND SI,01FH ;SI has hour
CMP [INTERNATVARS.Time_24],0
JNZ ISOK2 ;24 hour time?
CMP SI,12
JB ISOK ;Is AM
MOV [TCHAR],'p'
JZ ISOK ;Is 12-1p
SUB SI,12 ;Is PM
ISOK:
OR SI,SI
JNZ ISOK2
MOV SI,12 ;0 is 12a
ISOK2:
CALL CONVERT
MOV CX,1110H ;Supress at most 1 leading 0
MOV DL,AL
CALL OUTBYTE ;Print hour
MOV DL,BYTE PTR [INTERNATVARS.Time_sep]
CALL PRTCHR
MOV SI,DI
MOV CL,5
SHR SI,CL
AND SI,03FH ;SI has minute
CALL CONVERT
MOV CX,1000H ;Do not supress leading zeroes
MOV DL,AL
CALL OUTBYTE ;Print minute
MOV DL,[TCHAR]
CMP [INTERNATVARS.Time_24],0
JNZ NOAP ;24 hour time, no a or p
CALL PRTCHR ;Print a or p
NOAP:
MOV DX,OFFSET DG:IDPOST
CALL PRINT
MOV [DISPFLG],0
RET
CONVERT:
MOV CX,16
XOR AX,AX
CNVLOOP:
SHL SI,1
CALL CONVWRD
CLC
LOOP CNVLOOP
RET
SUBTTL Misc Routines - Mostly I/O
PAGE
CONVWRD:
ADC AL,AL
DAA
XCHG AL,AH
ADC AL,AL
DAA
XCHG AL,AH
RET1: RET
UNSCALE:
SHR CX,1
JC RET1
SHL SI,1
RCL DI,1
JMP SHORT UNSCALE
DISP16BITS:
MOV BYTE PTR DISPFLG,1
JMP SHORT DISP32BITS
DISPCLUS:
MUL [SSIZE]
MOV CL,[CSIZE]
XOR CH,CH
MOV SI,AX
MOV DI,DX
CALL UNSCALE
DISP32BITS:
PUSH BP
PUSH BX
XOR AX,AX
MOV BX,AX
MOV BP,AX
MOV CX,32
CONVLP:
SHL SI,1
RCL DI,1
XCHG AX,BP
CALL CONVWRD
XCHG AX,BP
XCHG AX,BX
CALL CONVWRD
XCHG AX,BX
ADC AL,0
LOOP CONVLP
; Conversion complete
MOV CX,1310H ;Print 3-digit number with 2 leading blanks
CMP BYTE PTR DISPFLG,0
JNZ FOURDIG
MOV CX,1810H ;Print 8-digit number with 2 leading blanks
XCHG DX,AX
CALL DIGIT
XCHG AX,BX
CALL OUTWORD
FOURDIG:
MOV AX,BP
CALL OUTWORD
MOV BYTE PTR DISPFLG,0
POP DX
CALL PRINT
POP BP
RET
OUTWORD:
PUSH AX
MOV DL,AH
CALL OUTBYTE
POP DX
OUTBYTE:
MOV DH,DL
SHR DL,1
SHR DL,1
SHR DL,1
SHR DL,1
CALL DIGIT
MOV DL,DH
DIGIT:
AND DL,0FH
JZ BLANKZER
MOV CL,0
BLANKZER:
DEC CH
AND CL,CH
OR DL,30H
SUB DL,CL
CMP BYTE PTR DISPFLG,0
JZ PRTCHR
CMP DL,30H
JL RET2
PRTCHR:
MOV AH,STD_CON_OUTPUT
INT 21H
RET2: RET
PRINTCNT:
LODSB
MOV DL,AL
INT 21H
LOOP PRINTCNT
RET
EPRINT:
CALL CHECKERR
JNZ RET$1
JMP SHORT PRINT
DOCRLF:
MOV DX,OFFSET DG:CRLF
PRINT:
MOV AH,STD_CON_STRING_OUTPUT
INT 21H
RET$1: RET
DOTCOMBMES:
CMP [NOISY],0
JZ SUBERRP
PUSH DX
CALL PRINTCURRDIRERR
MOV DX,OFFSET DG:CENTRY
CALL EPRINT
POP DX
CALL EPRINT
CALL DOCRLF
RET
SUBERRP:
MOV AL,1
XCHG AL,[ERRSUB]
CMP AL,0
JNZ RET32
MOV SI,OFFSET DG:NUL
CALL PRINTCURRDIRERR
MOV DX,OFFSET DG:BADSUBDIR
CALL EPRINT
RET32: RET
FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI
MOV CX,8
MAINNAME:
LODSB
CMP AL,' '
JZ SKIPSPC
STOSB
SKIPSPC:
LOOP MAINNAME
LODSB
CMP AL,' '
JZ GOTNAME
MOV AH,AL
MOV AL,'.'
STOSB
XCHG AL,AH
STOSB
MOV CL,2
EXTNAME:
LODSB
CMP AL,' '
JZ GOTNAME
STOSB
LOOP EXTNAME
GOTNAME:
XOR AL,AL
STOSB
RET
CODE ENDS
END CHKDSK