home *** CD-ROM | disk | FTP | other *** search
- _TEXT SEGMENT PUBLIC 'CODE'
- ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
- ORG 100H
- START: JMP MAIN
-
- ; DATA AREA
- ; ---------
- SIGNATURE DB CR,SPACE,SPACE,SPACE,CR,LF
- COPYRIGHT DB "SHRED 1.0 (c) 1995 Michael J. Mefford",CR,LF
- First_Rights DB "First Published in PC Magazine, "
- DB "January 10, 1995",CR,LF,LF
-
- DB "Syntax: SHRED [d:] [filespec] [/S] [/F | /D] [/C]",CR,LF,LF
- DB "Insures confidentiality by writing zeros over sensitive data",CR,LF
- DB "/S Subdirectories.",CR,LF
- DB "/F Free space on disk shredded.",CR,LF
- DB "/D Delete only; no shredding.",CR,LF
- DB "/C Confirmation before shredding suppressed."
-
- DOUBLE_SPACE DB LF
- CR_LF DB CR,LF,0,CTRL_Z
-
- CR EQU 13
- LF EQU 10
- CTRL_Z EQU 26
- SPACE EQU 32
- BOX EQU 254
-
- Y_SCAN EQU 15H
- N_SCAN EQU 31H
- ESC_SCAN EQU 01H
- CTRL_C EQU 03H
- ENTER_SCAN EQU 1CH
- DIRECTORY EQU 10H
-
- MATCHING STRUC
- RESERVED DB 21 DUP (?)
- ATTRIBUTE DB ?
- FILE_TIME DW ?
- FILE_DATE DW ?
- SIZE_LOW DW ?
- SIZE_HIGH DW ?
- FILE_NAME DB 13 DUP (?)
- MATCHING ENDS
-
- BYTES_PER_CLUSTER DW ?
- AVAILABLE_HIGH DW ?
- AVAILABLE_LOW DW ?
-
- ZERO_SEG DW ?
- CTRL_BREAK DB ?
- CURRENT_DISK DB ?
- FILESPEC DW ?
- DIRECTORY_LINE DW ?
- OPEN_FORMAT DW 3C00H ;Create file.
-
- SWITCH_FLAG DB 0
- SUBDIRS EQU 01H
- FREE EQU 02H
- DELETE_ONLY EQU 04H
- CONFIRM EQU 08H
- DISK EQU 10H
-
- NOT_FOUND DB CR,LF,"File not found",0
- NOT_ENOUGH DB "Not enough memory",0
- DIRECTORY_OF DB "Directory of ",0
- SHREDDING DB "Shredding ",0
- DELETING DB "Deleting ",0
- FREE_SPACE DB "All the FREE space of drive ",0
- WILL_BE DB "will be ",0
- SHREDDED DB "shredded. ",0
- DELETED DB "deleted. ",0
- WORKING DB "... working",0
- WARNING DB "WARNING: ",0
- CONTINUE DB "Continue? (Y/N or Esc to Quit) ",0
- TO_CONFIRM DB CR,LF,"(Press ",17,217," to confirm, Esc to cancel) ",0
- ABORTED DB CR,LF,LF,"Aborted",CR,LF,0
- TEMP DB "SHRED.TMP",0
- STAR_DOT_STAR DB "*.*",0
- DOT_DOT DB "..",0
- PROTECTED_FILE DB "is a read-only and can't be shredded. Press any key.",0
-
- ; CODE AREA
- ; ---------
-
- MAIN PROC NEAR
- CLD ;String moves forward.
- MOV AX,500H
- INT 10H ;Select active page zero.
-
- MOV AH,0FH
- INT 10H ;Get current video mode.
- CMP AL,7 ;If it's MONO,
- JZ CK_CURSOR
- CMP AL,2 ; CO80,
- JZ CK_CURSOR
- CMP AL,3 ; or BW80, then OK mode.
- JZ CK_CURSOR
- MOV AX,3 ;Else, change to CO80.
- INT 10H
-
- CK_CURSOR: CALL GET_CURSOR ;Read cursor position.
- CMP DH,1 ;If DOS prompt already
- JZ SIGN_ON ; at top, skip move.
-
- MOV AH,8 ;Else, read attr/char
- INT 10H ; at cursor position.
- MOV BH,AH ;Move DOS command line to top
- XOR CX,CX ; of screen by scrolling active
- MOV DL,80 - 1 ; page with current attribute.
- MOV AL,DH
- DEC AL
- MOV AH,6
- INT 10H
-
- SIGN_ON: MOV DX,100H ;Set cursor to line 2 (logical 1)
- CALL SET_CURSOR
- MOV SI,OFFSET SIGNATURE ;And display copyright
- CALL PRINT_STRING ; and syntax.
-
- MOV BX,OFFSET ZEROS ;Allocate memory for code, stack
- ADD BX,15 ; and 64K for a segment of zeros.
- MOV CL,4
- SHR BX,CL
- MOV AX,DS
- ADD AX,BX
- MOV ZERO_SEG,AX ;Save address of segment of zeros
- ADD BX,4096
- MOV AH,4AH
- INT 21H
- JNC SETUP_STACK
- MOV SI,OFFSET NOT_ENOUGH ;Error msg if not enough memory.
- JMP MSG_EXIT
-
- SETUP_STACK: MOV SP,OFFSET STACK_PTR ;Move stack pointer down.
- MOV DX,OFFSET DTA ;To preserve command line, change
- MOV AH,1AH ; DTA from PSP to end of code.
- INT 21H
-
- MOV ES,ZERO_SEG ;Fill extra segment with zeros.
- XOR DI,DI
- XOR AX,AX
- MOV CX,32768
- REP STOSW
- PUSH CS
- POP ES
-
- MOV AX,3300H ;Retrieve current Ctrl
- INT 21H ; break state and store.
- MOV CTRL_BREAK,DL
- XOR DL,DL
- MOV AX,3301H ;Turn Ctrl break off.
- INT 21H
-
- MOV AH,19H ;Get current drive
- INT 21H
- MOV CURRENT_DISK,AL ; and save.
-
- ;----------------------------------------------;
- PARSE: MOV SI,81H ;Point to command line parameter.
- FIND_SWITCH: LODSB ;Get a byte.
- CMP AL,CR ;Carriage return marks end.
- JZ FIND_FILESPEC ;If end, done here.
- CMP AL,"/" ;Is it a switch character?
- JNZ FIND_SWITCH ;If no, next byte.
- LODSB ;Else, retrieve switch.
- AND AL,5FH ;Else, capitalize.
- CMP AL,"S" ;Is it subdirectories?
- JNZ CK_FREE ;If no, check free switch.
- OR SWITCH_FLAG,SUBDIRS ;Else, flag to do subdirectories.
- CK_FREE: CMP AL,"F" ;Is it disk free switch?
- JNZ CK_DELETE ;If no, check delete switch.
- OR SWITCH_FLAG,FREE ;Else, flag to zero free space.
- CK_DELETE: CMP AL,"D" ;Is it delete-only switch?
- JNZ CK_CONFIRM ;If no, check confirm switch.
- OR SWITCH_FLAG,DELETE_ONLY ;Else, flag to delete-only.
- CK_CONFIRM: CMP AL,"C" ;Is it suppress confirm switch?
- JNZ BAD_SWITCH ;If no, exit.
- OR SWITCH_FLAG,CONFIRM ;Else, flag to suppress prompts.
- JMP FIND_SWITCH ;Next switch.
- BAD_SWITCH: MOV AL,1
- JMP RESTORE
-
- ;------------------------------------------------------------------;
- ; Parse drive and/or path delimiters. Convert filespec to ASCIIZ. ;
- ; If drive delimiter found (:), change to requested drive. ;
- ;------------------------------------------------------------------;
- FIND_FILESPEC: MOV SI,81H ;Point to command line parameter.
- PARSE_LEADING: LODSB ;Get a byte.
- CMP AL,SPACE ;Is it a space char or below?
- JA LEADING_END ;If no, done here.
- CMP AL,CR ;Is it carriage return?
- JNZ PARSE_LEADING ;If no, get next byte.
- LEADING_END: DEC SI ;Adjust pointer to string start.
- MOV BP,SI ;Save start of filespec.
- MOV BX,SI ;Use BX as filename start pointer
-
- FIND_END: LODSB ;Get a byte.
- CMP AL,":" ;Is it a drive delimiter?
- JNZ CK_SLASH ;If no, check path delimiter.
- MOV DL,[SI-2] ;Else, retrieve drive specifier.
- AND DL,5FH ;Capitalize.
- SUB DL,"A" ;Convert to DOS format.
- MOV AH,0EH ;Change drive.
- INT 21H
- MOV BX,SI ;Save as filename start.
- JMP FIND_END ;Continue parsing.
-
- CK_SLASH: CMP AL,"\" ;Is it a path delimiter?
- JNZ CK_DELIMITER ;If no, check switch character.
- MOV BX,SI ;Else, save as filename start.
- CK_DELIMITER: CMP AL,"/" ;Is it a switch delimiter?
- JZ FOUND_END ;If yes, end of filespec.
- CMP AL,SPACE ;Is it above space character?
- JA FIND_END ;If yes, continue until find end.
-
- FOUND_END: DEC SI ;Adjust.
- PUSH SI ;Save filespec end.
- PUSH BX ;Save filespec start.
- MOV BYTE PTR [SI],0 ;Convert to ASCIIZ.
- CMP BP,SI ;Any filespec?
- JZ NO_SPEC ;If no, treat as /F.
- CMP BYTE PTR [SI - 1],":" ;Drive specifier only?
- JNZ GET_CURRENT ;If no, skip
- NO_SPEC: OR SWITCH_FLAG,DISK
-
- GET_CURRENT: MOV SI,OFFSET CURRENT_DIR ;Retrieve current directory.
- CALL GET_DIR
- MOV AH,19H ;Retrieve current disk.
- INT 21H
- ADD AL,"A" ;Convert to ASCII.
- MOV BYTE PTR WORKING_DIR,AL ;Save drive
- MOV BYTE PTR WORKING_DIR + 1,":" ; and colon delimiter.
-
- CALL GET_AVAILABLE ;Get disk free space.
-
- TEST SWITCH_FLAG,FREE OR DISK ;Was there /F or no filespec
- JZ FIND_PATH ; or drive-only?; If no, skip.
- TEST SWITCH_FLAG,DELETE_ONLY ;Was there /D delete only?
- JNZ FIND_PATH ;If yes, skip.
- CALL SHRED_FREE ;Else, shred free disk space.
- MOV SI,OFFSET DOUBLE_SPACE ;Add double space
- CALL PRINT_STRING ; between outputs.
-
- ;-------------------------------------------------;
- FIND_PATH: POP BX ;Retrieve filename start.
- POP SI ;Retrieve filespec end.
- TEST SWITCH_FLAG,DISK ;Was filespec drive-only?
- JZ CK_ROOT ;If no, continue.
- JMP GOOD_EXIT ;Else, done.
-
- CK_ROOT: MOV CX,1 ;CX=1:"\"not=root; CX=0:"\"=root.
- CMP BYTE PTR [BX - 1],"\" ;Filespec start path delimiter?
- JNZ CK_PATH ;If no, not root.
- CMP BYTE PTR [BX - 2],":" ;Else, is it prefaced with colon?
- JZ ROOT ;If yes, then root.
- CMP BYTE PTR [BX - 2],SPACE ;Is it prefaced with white space?
- JA CK_TRAILING ;If no, then trailing slash?
- ROOT: DEC CX ;Else, root; CX=0 for root flag.
- JMP SHORT CK_PATH ;Change default path.
-
- CK_TRAILING: CMP BX,SI ;Filename start = filespec end?
- JNZ CK_PATH ;If no, not trailing slash.
- MOV BYTE PTR [BX - 1],0 ;Else, zero out trailing slash
- MOV BX,OFFSET STAR_DOT_STAR ; and use global filespec.
-
- CK_PATH: MOV DX,BP ;See if filespec is a path
- CALL CHANGE_DIR ; by changing directory.
- JC CK_FILESPEC ;If failed, remove filename.
- MOV BX,OFFSET STAR_DOT_STAR ;Else, use global for filename.
- JMP SHORT GOT_FILESPEC ;Done here.
-
- CK_FILESPEC: JCXZ SAVE_DELIMIT ;Is path root?; If yes leave "\".
- DEC BX ;Else, point to slash.
- SAVE_DELIMIT: PUSH [BX] ;Preserve filename start.
- MOV BYTE PTR [BX],0 ;Temp ASCIIZ twixt path and name.
- CALL CHANGE_DIR ;Change directory.
- POP [BX] ;Restore first byte of filename.
- JCXZ GOT_FILESPEC ;If root, done here.
- INC BX ;Else, readjust filename pointer.
- GOT_FILESPEC: MOV FILESPEC,BX ;Save filename.
-
- ;----------------------------------------------;
- MOV BP,OFFSET TREE_LEVEL ;Initialize directory tree
- MOV DI,BP ; level array to level one.
- MOV AX,0101H
- MOV CX,50
- REP STOSW
- CALL GET_CURSOR ;Get relative line for
- MOV DIRECTORY_LINE,DX ; directory display.
- MOV OPEN_FORMAT,3D01H ;Open file for writing.
-
- NEXT_LEVEL: MOV SI,OFFSET WORKING_DIR + 2 ;Display current directory.
- CALL GET_DIR
- MOV SI,OFFSET DIRECTORY_OF
- CALL PRINT_STRING
- MOV SI,OFFSET WORKING_DIR
- CALL PRINT_STRING
-
- FIND_FIRST: MOV DX,FILESPEC ;Find first matching normal
- XOR CX,CX ; file to filespec.
- MOV AH,4EH
- INT 21H
- JNC CK_READ_ONLY
- MOV SI,OFFSET NOT_FOUND ;If failed, display message.
- CALL PRINT_STRING
- JMP SHORT CK_SUBDIRS ;Check /Subdir switch.
-
- FIND_NEXT: MOV AH,4FH ;Find next matching file.
- INT 21H
- JC CK_SUBDIRS ;If failed, check /Subdir switch.
-
- CK_READ_ONLY: TEST BYTE PTR DTA.ATTRIBUTE, 1
- JZ CK_WARNING
- MOV DX,DIRECTORY_LINE
- INC DH
- CALL BLANK_LINE
- CALL DISPLAY_NAME
- MOV SI,OFFSET PROTECTED_FILE
- CALL PRINT_STRING
- CALL CLEAR_KEY
- CALL GET_KEY
- JMP FIND_NEXT
-
- CK_WARNING: MOV DX,DIRECTORY_LINE ;Move cursor to line below
- INC DH ; directory.
- CALL BLANK_LINE ;Blank out last display.
- TEST SWITCH_FLAG,CONFIRM ;Did user suppress prompts?
- JNZ NO_WARNING ;If yes, no warning.
- MOV SI,OFFSET WARNING ;Else, display warning message.
- CALL PRINT_STRING
- CALL DISPLAY_NAME ;Display complete stats of file.
- MOV SI,OFFSET WILL_BE
- CALL PRINT_STRING ;Display message.
- TEST SWITCH_FLAG,DELETE_ONLY
- JZ MESSAGE1
- MOV SI,OFFSET DELETED
- MESSAGE1: CALL PRINT_STRING
- CALL PROMPT ;Ask user if should continue.
- JC FIND_NEXT ;If no, find next matching.
- CALL SHRED_FILE ;Else, shred the file.
- JMP FIND_NEXT ;Find next matching file.
-
- NO_WARNING: CALL CK_KEY ;Let user abort the /C suppress
- JNZ ERROR_EXIT ; confirm mode with any keypress.
- MOV SI,OFFSET SHREDDING ;Display message
- TEST SWITCH_FLAG,DELETE_ONLY
- JZ MESSAGE2
- MOV SI,OFFSET DELETING
- MESSAGE2: CALL PRINT_STRING
- CALL DISPLAY_NAME ; and file stats.
- CALL SHRED_FILE ;Shred the file.
- JMP FIND_NEXT ;Next matching.
-
- ;----------------------------------------------;
- CK_SUBDIRS: TEST SWITCH_FLAG,SUBDIRS ;Was there a /Subdir switch?
- JNZ FIRST_DIR ;If yes, continue.
- JMP SHORT GOOD_EXIT ;Else, exit.
-
- PARENT_DIR: CMP BP,OFFSET TREE_LEVEL ;Are we at tree level where we
- JZ GOOD_EXIT ; started? If yes, done here.
- MOV BYTE PTR [BP],1 ;Else, first dir of this level.
- DEC BP ;Go down a level.
- MOV DX,OFFSET DOT_DOT ;Change to parent directory.
- CALL CHANGE_DIR
-
- FIRST_DIR: XOR BL,BL ;BL = directory number.
- MOV DX,OFFSET STAR_DOT_STAR ;Global search.
- MOV CX,DIRECTORY ;Ask for directories.
- MOV AH,4EH
- INT 21H
- JC PARENT_DIR ;If no match, down a level.
- JMP SHORT CK_DIR ;Else, see if it's a directory.
-
- NEXT_DIR: MOV AH,4FH ;Get all subdirectories in
- INT 21H ; current directory then
- JC PARENT_DIR ; to parent.
-
- CK_DIR: CMP BYTE PTR DTA.ATTRIBUTE,DIRECTORY ;Is it a directory?
- JNZ NEXT_DIR ;If no, next matching.
- CMP BYTE PTR DTA.FILE_NAME,'.' ;is it a dot directory?
- JZ NEXT_DIR ;If no, next matching.
- INC BL ;Increment position in directory.
- CMP BL,[BP] ;Continue until new directory.
- JNZ NEXT_DIR
- INC BYTE PTR DS:[BP] ;Update this level dir count.
- MOV DX,OFFSET DTA.FILE_NAME
- CALL CHANGE_DIR ;Change the directory.
- INC BP ;Up a level.
- MOV DX,DIRECTORY_LINE ;Blank out last display.
- CALL BLANK_LINE
- JMP NEXT_LEVEL ;Get all files in new directory.
-
- ;----------------------------------------------;
- ERROR_EXIT: MOV SI,OFFSET ABORTED ;Display abort message.
- MSG_EXIT: CALL PRINT_STRING
- MOV AL,1 ;ERRORLEVEL = 1.
- JMP SHORT RESTORE ;Restore defaults.
-
- GOOD_EXIT: XOR AL,AL ;ERRORLEVEL = 0.
-
- RESTORE: PUSH AX ;Save ERRORLEVEL.
- MOV DL,CTRL_BREAK ;Restore break state.
- MOV AX,3301H
- INT 21H
- MOV DX,OFFSET CURRENT_DIR ;Restore default directory.
- CALL CHANGE_DIR
- MOV DL,CURRENT_DISK ;Restore default drive.
- MOV AH,0EH
- INT 21H
- POP AX ;Retrieve ERRORLEVEL.
- EXIT: MOV AH,4CH
- INT 21H ;Terminate.
- MAIN ENDP
-
- ;***************;
- ;* SUBROUTINES *;
- ;***************;
- SHRED_FREE: PUSH BP ;Preserve base pointer.
- MOV DX,OFFSET TEMP ;See if temporary file exits.
- MOV CX,1FH ;Use all attributes.
- NEXT_TEMP: MOV AH,4EH
- INT 21H
- JC GOT_TEMP ;If it doesn't, OK.
- MOV BX,DX
- INC BYTE PTR [BX] ;Else, change name.
- JNZ NEXT_TEMP ;Give up after several name
- JMP ERROR_EXIT ; changes and abort.
-
- GOT_TEMP: MOV BP,DX ;Point to temporary filename.
- TEST SWITCH_FLAG,CONFIRM ;Do we need user permission to
- JNZ NO_PROMPT ; continue? If no, no prompt.
-
- CALL FREE_MSG ;Else, display message.
- MOV SI,OFFSET WILL_BE
- CALL PRINT_STRING
- MOV SI,OFFSET WILL_BE
- CALL PRINT_STRING
- CALL PRINT_STRING
- MOV SI,OFFSET CR_LF
- CALL PRINT_STRING
- CALL PROMPT ;Ask user if should continue.
- JC FREE_END ;If no, done here.
- JMP SHORT DO_FREE ;Else, shred the disk free space.
-
- NO_PROMPT: CALL CK_KEY ;Let user abort the /C suppress
- JNZ ERROR_EXIT ; confirm mode with any keypress.
- MOV SI,OFFSET SHREDDING ;Display message.
- CALL PRINT_STRING
- CALL FREE_MSG
- MOV SI,OFFSET WORKING ;Display "... working" message.
- CALL PRINT_STRING
-
- DO_FREE: MOV SI,AVAILABLE_HIGH ;Create a temporary file and
- MOV DI,AVAILABLE_LOW ; write zeros bytes equal to
- CALL WRITE_ZEROS ; the amount of free space.
- FREE_END: POP BP ;Restore base pointer.
- RET
-
- ;----------------------------------------------;
- FREE_MSG: MOV SI,OFFSET FREE_SPACE ;Display free space message.
- CALL PRINT_STRING
- MOV AL,BYTE PTR WORKING_DIR ;Display the working drive.
- MOV AH,0EH
- INT 10H
- MOV AX,0EH SHL 8 + SPACE
- INT 10H
- RET
-
- ;----------------------------------------------;
- SHRED_FILE: PUSH BP ;Preserve base pointer.
- MOV BP,OFFSET DTA.FILE_NAME ;Point to filename.
- MOV SI,DTA.SIZE_HIGH ;Retrieve size of file.
- MOV DI,DTA.SIZE_LOW
- MOV DX,SI
- MOV AX,DI
- MOV CX,BYTES_PER_CLUSTER ;Round up file size to nearest
- DIV CX ; whole cluster by dividing by
- SUB CX,DX ; bytes per cluster and
- ADD DI,CX ; adding remainder to size.
- ADC SI,0
- CALL WRITE_ZEROS ;Write zeros over the file.
- POP BP ;Restore base pointer.
- RET
-
- ;---------------------------------------------------------------;
- ; INPUT: BP -> filename; SI:DI = number of zero bytes to write. ;
- ;---------------------------------------------------------------;
- WRITE_ZEROS: TEST SWITCH_FLAG,DELETE_ONLY ;Is the delete-only flag set?
- JNZ DELETE_FILE ;If yes, don't write zeros.
- MOV DX,BP ;Filename pointer.
- XOR CX,CX ;Normal attribute.
- MOV AX,OPEN_FORMAT ;Create new or open existing.
- INT 21H
- JC WRITE_FAIL ;If failed, exit.
- MOV BX,AX ;Else, save filehandle.
-
- NEXT_WRITE: MOV CX,DI ;Retrieve low half of byte count.
- OR SI,SI ;Is high half zero?
- JZ SUBTRACT ;If yes, continue.
- MOV CX,0FFFFH ;Else, write full word (65535).
- SUBTRACT: SUB DI,CX ;Subtract from running count.
- SBB SI,0 ;If borrow, adjust high half.
- JCXZ CLOSE_FILE ;If zero bytes, done here.
-
- PUSH DS ;Preserve data segment.
- MOV DS,ZERO_SEG ;Use segment of zeros.
- XOR DX,DX ;Offset of zero.
- MOV AH,40H ;Write to file.
- INT 21H
- POP DS ;Restore data segment.
- JC WRITE_FAIL ;If failed, exit.
- CMP AX,CX ;Did we write what we asked?
- JNZ WRITE_FAIL ;If no, failed; exit.
- JMP NEXT_WRITE ;Else, write next chunk.
-
- CLOSE_FILE: MOV AH,3EH ;Close file.
- INT 21H
- JC WRITE_FAIL ;If failed, exit.
- DELETE_FILE: MOV DX,BP
- MOV AH,41H ;Delete file.
- INT 21H
- JC WRITE_FAIL ;If failed, exit.
- ZEROS_END: RET
-
- WRITE_FAIL: MOV DX,OFFSET NOT_FOUND ;With all failures, display
- CALL PRINT_STRING ; generic "file not found"
- JMP ERROR_EXIT ; message and abort.
-
- ;----------------------------------------------------------------------;
- ; OUTPUT: CY = 0: Yes; CY = 1: No; If Esc or ^C, go directly to exit. ;
- ;----------------------------------------------------------------------;
- PROMPT: MOV SI,OFFSET CONTINUE ;Display message.
- CALL PRINT_STRING
- CALL CLEAR_KEY ;Clear keyboard buffer.
- GET_INPUT: CALL GET_KEY ;Now get a keystroke.
- CMP AH,Y_SCAN ;Was it "Y"?
- JNZ CK_NO
- MOV AH,0EH ;If yes, display "Y" and
- INT 10H
- CALL PRINT_STRING ; ask for confirmation.
- GET_CONFIRM: CALL GET_KEY
- CMP AH,ESC_SCAN
- STC
- JZ PROMPT_END
- CMP AH,ENTER_SCAN
- JNZ GET_CONFIRM
- MOV SI,OFFSET WORKING
- CALL PRINT_STRING
- CLC
- JMP SHORT PROMPT_END
-
- CK_NO: CMP AH,N_SCAN ;Was it "N"?
- STC
- JZ PROMPT_END
- CMP AH,ESC_SCAN ;Was it Esc?
- JZ BREAK
- OR AH,AH ;Was it Ctrl Break?
- JZ BREAK
- CMP AL,CTRL_C ;Was it Ctrl C?
- JNZ GET_INPUT ;If Esc, Ctrl Break or Ctrl C,
- BREAK: JMP ERROR_EXIT ; immediate exit.
- PROMPT_END: RET ;Else, return keystroke.
-
- ;----------------------------------------------;
- GET_AVAILABLE: XOR DL,DL ;Default drive.
- MOV AH,36H ;Get disk free space.
- INT 21H
- MUL CX ;Bytes/sector * sectors/cluster
- MOV BYTES_PER_CLUSTER,AX ; equals bytes/cluster.
- MUL BX ;Avail clusters * bytes/cluster
- MOV AVAILABLE_HIGH,DX ; equals available bytes.
- MOV AVAILABLE_LOW,AX
- RET
-
- ;----------------------------------------------;
- DISPLAY_NAME: MOV SI,OFFSET DTA.FILE_NAME ;Point to filename.
- MOV DI,OFFSET RESULTS ;And storage area.
- MOV AX,SPACE SHL 8 + SPACE ;Initiate storage with spaces.
- MOV CX,20
- REP STOSW
- MOV DI,OFFSET RESULTS ;Point to start of storage again.
- MOV CX,12 ;Store 12 bytes of filename.
- NEXT_STORE: LODSB ;Get a byte.
- OR AL,AL ;End of filename?
- JZ END_STORE ;If yes, finish with blanks.
- CMP AL,"." ;Is it the period?
- JNZ STORE_BYTE ;If no, store.
- SUB CX,3 ;Else store 3 spaces.
- MOV AL,SPACE
- REP STOSB
- ADD CX,3
- JMP SHORT NEXT_STORE ;Get next byte.
-
- STORE_BYTE: STOSB ;Store byte.
- LOOP NEXT_STORE ;Get next byte.
- END_STORE: MOV AL,SPACE ;Pad balance with spaces.
- REP STOSB
-
- PUSH DI ;Save pointer.
- ADD DI,8 ;Move to end of bytes field.
- MOV DX,DTA.SIZE_LOW ;Retrieve high and low words
- MOV AX,DTA.SIZE_HIGH ; of size in bytes.
- MOV BX,10 ;Convert to decimal.
- STD ;Reverse direction.
-
- NEXT_SIZE: MOV CX,DX ;Low word in CX.
- XOR DX,DX ;Zero in high half.
- DIV BX ;Convert to decimal.
- XCHG AX,CX ;Retrieve low word.
- DIV BX
- XCHG AX,DX ;Retrieve remainder.
- ADD AL,"0" ;Convert to ASCII.
- STOSB ;Store it.
- MOV AX,CX ;Are we done?
- OR CX,DX
- JNZ NEXT_SIZE ;If no, divide again.
-
- CLD ;Back to forward direction.
- POP DI ;Retrieve pointer.
- ADD DI,11 ;Move to date field.
- DATE: MOV DX,DTA.FILE_DATE ;Retrieve date.
- MOV AX,DX
- MOV CL,5 ;Shift to lowest bits.
- SHR AX,CL
- AND AX,1111B ;Mask off all but month.
- MOV CL,0FFH ;Flag as no leading zeros.
- MOV CH,"-" ;Delimiting character.
- CALL STORE_WORD ;Store it.
-
- MOV AX,DX ;Retrieve date.
- AND AX,11111B ;Mask off all but day.
- XOR CL,CL ;Flag include leading zeros.
- MOV CH,"-"
- CALL STORE_WORD ;Store it.
-
- MOV AX,DX ;Retrieve date for last time.
- MOV CL,9
- SHR AX,CL ;Mask off all but year.
- ADD AX,80 ;Adjust to ASCII.
- CMP AX,100 ;Past year 2000?
- JB DISPLAY_DATE ;If no, display. Else, adjust for
- SUB AX,100 ; next century. (Planning ahead!)
- DISPLAY_DATE: XOR CL,CL ;Display leading zeros.
- MOV CH,SPACE
- CALL STORE_WORD ;Store it.
-
- TIME: INC DI ;Move to time field.
- MOV DX,DTA.FILE_TIME ;Retrieve time.
- MOV AX,DX
- MOV CL,11 ;Shift to hours bits.
- SHR AX,CL
- PUSH AX
- CMP AX,12 ;Past noon?
- JBE MERIDIAN
- SUB AX,12 ;If yes, adjust.
- MERIDIAN: CMP AX,0 ;Midnight?
- JNZ NOT_MIDNIGHT
- MOV AX,12 ;If yes, adjust.
- NOT_MIDNIGHT: MOV CL,0FFH ;Suppress leading zeros.
- MOV CH,":"
- CALL STORE_WORD ;Store it.
-
- MOV AX,DX ;Retrieve time.
- MOV CL,5 ;Shift to minutes bits.
- SHR AX,CL
- AND AX,111111B ;Mask off all but minutes.
- XOR CL,CL
- POP DX ;Retrieve hours.
- MOV CH,"p" ;Assume PM.
- CMP DX,12 ;Is it PM?
- JAE PM
- MOV CH,"a" ;If no, AM.
-
- PM: CALL STORE_WORD ;Store it.
- XOR AL,AL
- STOSB
- MOV SI,OFFSET RESULTS ;Print out results
- CALL PRINT_STRING
- MOV SI,OFFSET CR_LF
- CALL PRINT_STRING
- RET ;Done here.
-
- ;-----------------------------------------------------------------------;
- ; Converts a two byte hex number to decimal followed by delimiter. ;
- ; INPUT: AX = hex number; BL = 10; CH = delimiter character to store. ;
- ; CL = 0 if zeros are to be stored; CL = -1 if leading zeros ignored. ;
- ; ES:DI points to storage. ;
- ;-----------------------------------------------------------------------;
- STORE_WORD: DIV BL ;Divide by ten.
- ADD AX,"00" ;Convert to ASCII.
- CMP CL,0 ;Are we to display leading zero?
- JZ STORE_IT ;If yes, store as is.
- CMP AL,"0" ;Is it a leading zero?
- JNZ STORE_IT ;If no, store it.
- MOV AL,SPACE ;Else, store a space.
- STORE_IT: STOSW
- MOV AL,CH ;Store delimiter character also.
- STOSB
- RET
-
- ;----------------------------------------------;
- ; INPUT: DX = first row to write spaces. ;
- ;----------------------------------------------;
- BLANK_LINE: PUSH DX
- CALL SET_CURSOR
- MOV CX,80 * 4
- NEXT_BLANK: MOV AX,0EH SHL 8 + SPACE ;Write spaces via BIOS.
- INT 10H
- LOOP NEXT_BLANK
- POP DX
- CALL SET_CURSOR
- RET
-
- ;----------------------------------------------;
- GET_DIR: MOV BYTE PTR [SI],"\" ;DOS doesn't preface directory
- INC SI ; with slash so we must.
- XOR DL,DL
- MOV AH,47H ;Get current directory.
- INT 21H
- RET
-
- CHANGE_DIR: MOV AH,3BH ;Change current directory.
- INT 21H
- RET
-
- ;----------------------------------------------;
- SET_CURSOR: XOR BH,BH ;Video page zero.
- MOV AH,2 ;Set cursor position.
- INT 10H
- RET
-
- GET_CURSOR: XOR BH,BH
- MOV AH,3 ;Get cursor position.
- INT 10H
- RET
-
- ;----------------------------------------------;
- GET_KEY: XOR AH,AH ;Get a keystroke.
- INT 16H
- RET
-
- CK_KEY: MOV AH,1 ;ZR = 1 if no keystroke available
- INT 16H ;ZR = 0 if keystroke is available
- RET
-
- CLEAR_IT: CALL GET_KEY
- CLEAR_KEY: CALL CK_KEY ;If any keystrokes available,
- JNZ CLEAR_IT ; remove them.
- RET
-
- ;----------------------------------------------;
- WRITE_TTY: MOV AH,0EH ;Write TTY via BIOS.
- INT 10H
- PRINT_STRING: LODSB
- OR AL,AL ;ASCIIZ string.
- JNZ WRITE_TTY
- RET
-
- CURRENT_DIR = $
- WORKING_DIR = CURRENT_DIR + 68
- RESULTS = WORKING_DIR + 68
- DTA = RESULTS + 41
- TREE_LEVEL = DTA + SIZE MATCHING
- STACK_PTR = TREE_LEVEL + 100 + 256
- ZEROS = STACK_PTR
-
- _TEXT ENDS
- END START