home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1987
/
21
/
co.asm
next >
Wrap
Assembly Source File
|
1987-10-26
|
80KB
|
1,741 lines
; Co.asm
; Format: CO [d:][directory]
CODE SEGMENT ;********************************;
ASSUME CS:CODE,DS:CODE ;* *;
ORG 100H ;* Requires MASM 2.0 or later *;
;* Remember to EXE2BIN *;
START: JMP BEGINNING ;* *;
;********************************;
; DATA AREA
; ---------
COPYRIGHT DB 10,"CO 1.0 (c) 1987 Ziff Communications Co.",13,10
PROGRAMMER DB 26,"Michael J. Mefford"
FIELD_SIZE EQU 44
BAR_START EQU 323
COPY_MARK EQU 26
FCB EQU 5CH
CURRENT_DISK DB ?
STATUS_REG DW ?
VIDEO_SEG DW 0B000H
NORMAL DB 07H
INVERSE DB 70H
BAR_ATTRIBUTE DB 70H
CURSOR_TYPE DW ?
CUR_VERIFY DB 0
SORT_OFFSET DW 0
SORT_TABLE DW 0,12,9,3,13,8,29
SORT_FLAG DB 0
SEARCH_ATTRIB DW 17H
CUR_OFFSET DW BUFFER
CUR_FILE DW ?
END_OFFSET DW ?
PAGE_END DW 21 * 160 + BAR_START
COUNT DW 0
FILE_CNT DW 0
LINE DW BAR_START
SEARCH_COUNT DW ?
MARK_CNT DW 0
FILENAME_END DW ?
PURGE_DISK DB ?
READ_HANDLE DW ?
WRITE_HANDLE DW ?
SOURCE_ATTRIB DW ?
TARGET_ATTRIB DW ?
SIZE_LOW DW ?
SIZE_HIGH DW ?
SOURCE_TIME DW ?
SOURCE_DATE DW ?
FILE_NAME DW ?
COPY_FLAG DB 0
DELETE_FLAG DB 0
RENAME_FLAG DB 0
VERIFY_FLAG DB 0
DISPATCH_KEY DB 1,3BH,3CH,3DH,3EH,3FH,40H,4AH,4EH,12H,14H,1FH,20H,2EH,2FH
DB 31H,32H,41H,42H,43H,44H,47H,48H,49H,4FH,50H,51H,76H,84H
DISPATCH_CNT EQU $ - DISPATCH_KEY
DISPATCH_TABLE DW EXIT, COPY, DELETE, MOVE, CLEAR_MARK, MARK_BLANK, VERIFY
DW UNMARK, MARK, SORT_EXT, SORT_DATE, SORT_SIZE, DELETE
DW COPY, VERIFY, SORT_NAME, MOVE, SORT_NAME, SORT_EXT
DW SORT_SIZE, SORT_DATE, HOME_BAR, UP_ARROW, PG_UP
DW END_BAR, DN_ARROW, PG_DN, BOTTOM_BAR, TOP_BAR
DISPATCH_END EQU $ - 2
NOT_ENOUGH DB "Requires 128K free RAM$"
INVALID DB "Invalid directory$"
TOO_MANY DB "Too many files$"
LOADING DB "Loading and Sorting directory.",0
LOAD_ONLY DB "Loading directory.",0
DIRECTORY DB "Directory of ",0
FILES DB 4 DUP(32),"File(s)",11 DUP(32),"bytes free",0
DELETE_MSG DB " will be deleted.",0,"Do you wish to delete? Y/N",0
BS DB 8,32,8,0
DISK_MSG DB "Error reading drive ",0
DB "(R)etry or (Q)uit",0
MARKED_MSG DB " marked files",0
COPY_MSG DB "Copy ",0
MOVE_MSG DB "Move ",0
TO_MSG DB " to...",0
STAR_DOT_STAR DB "*.*",0
ON DB " ON",0
OFF DB "OFF",0
DIRECTORIES DB "<DIR>"
MENU LABEL BYTE
DB 201,20 DUP (205),187,186," PC Magazine CO.COM ",186
DB 186," (C) Copr. 1987 ZD ",186,186," Michael J. Mefford ",186
DB 199,20 DUP (196),182, 186," F1 Copy ",186
DB 186," F2 Delete ",186,186," F3 Move ",186
DB 186," F4 Clear marks ",186,186," F5 Mark blank ",186
DB 186," F6 Verify OFF ",186,186," F7 Sort by Name ",186
DB 186," F8 Sort by Ext. ",186,186," F9 Sort by Size ",186
DB 186," F10 Sort by DaTe ",186,186," +/- Mark/Unmark ",186
DB 186," Esc to Exit ",186,200,20 DUP (205),188
DB " Use: ",24,32,25," PgUp PgDn"
DB " ^PgUp ^PgDn Home End "
;----------------------------------------------------------------------------;
; Some housekeeping first. Since we will be changing the default drive ;
; and directory to the requested drive and directory, we need to save the ;
; current defaults, so they can be restored. Install critical error trap. ;
;----------------------------------------------------------------------------;
; CODE AREA
; ---------
BEGINNING: MOV AX,3301H ;Turn Control Break off.
MOV DL,0
INT 21H
MOV AH,54H ;Get current verify flag.
INT 21H
MOV CUR_VERIFY,AL ; and save.
XOR AL,AL
CALL SET_VERIFY ;Turn verify off.
MOV DX,OFFSET DISK_ERROR ;Install critical error trap.
MOV AX,2524H
INT 21H
CLD ;String moves forward.
CALL GET_DRIVE ;Get current drive.
MOV CURRENT_DISK,AL ;Save.
MOV SI,OFFSET CURRENT_DIR ;Get current directory.
CALL GET_DIR
;---------------------------------------------------------------------;
; More housekeeping. We will be writing directly to the screen buffer ;
; so we need the display card address and the status register. ;
;---------------------------------------------------------------------;
DISPLAY: MOV AX,40H ;Point to the ROM BIOS data area
MOV DS,AX ; and get base address of active
MOV AX,DS:[63H] ; display card.
ADD AX,6 ;Add six to get status register
PUSH CS ;Done there, so restore data segment.
POP DS
MOV STATUS_REG,AX ;Store status register.
CMP AX,3BAH ;Status port of MONO card is 3BAh.
JZ MONO ;If that's what we got, it's MONO
MOV VIDEO_SEG,0B800H ; else COLOR so add 800h.
XOR BH,BH ;Get current attribute
MOV AH,8 ; of display page zero.
INT 10H
MOV NORMAL,AH ;Store it.
XOR AH,1110111B ;Flip color bits.
MOV INVERSE,AH ;Save it.
MOV BAR_ATTRIBUTE,AH
MONO: XOR BH,BH
MOV AH,3 ;Retrieve cursor type.
INT 10H
MOV CURSOR_TYPE,CX
MOV AH,49H ;Return our memory segment.
INT 21H
MOV BX,2000H ;Request 128K.
MOV AH,4AH
INT 21H
MOV DX,OFFSET NOT_ENOUGH
JNC PARSE
JMP ERROR_EXIT ;If not available, exit.
;----------------------------------------;
; Parse the command line for parameters. ;
;----------------------------------------;
PARSE: MOV SI,81H ;Point to first character.
CMP BYTE PTR DS:[80H],0 ;Any parameters?
JNZ NEXT_SWITCH
JMP GET_WORKING ;If no, skip.
NEXT_SWITCH: LODSB ;Get a byte.
CMP AL,13 ;Carriage return?
JZ GET_PARA ;If yes, done here.
CMP AL,"/" ;Is it switch character?
JNZ NEXT_SWITCH ;If no, get next character.
LODSB ;Get switch character.
AND AL,5FH ;Capitalize.
CMP AL,"R" ;If "R", remove directories.
JNZ CK_EXT
MOV SEARCH_ATTRIB,7
CK_EXT: CMP AL,"E" ;If "E", sort by extension.
JNZ CK_SIZE
MOV SORT_OFFSET,4
CK_SIZE: CMP AL,"S" ;If "S", sort by size.
JNZ CK_DATE
MOV SORT_OFFSET,8
CK_DATE: CMP AL,"D" ;If "D", sort by date.
JZ GOT_DATE
CMP AL,"T" ;If "T", sort by date.
JNZ CK_ORIGINAL
GOT_DATE: MOV SORT_OFFSET,12
CK_ORIGINAL: CMP AL,"O" ;If "O", don't sort at all.
JNZ NEXT_SWITCH
MOV SORT_FLAG,1
JMP SHORT NEXT_SWITCH
GET_PARA: XOR BL,BL ;Assume no drive request.
MOV SI,81H ;Point to first character.
NEXT_PARSE: LODSB
CMP AL,13 ;Carriage return or slash?
JZ GET_WORKING ;If yes, done here.
CMP AL,"/"
JZ GET_WORKING
CMP AL,32 ;Leading space?
JBE NEXT_PARSE ;If yes, get next byte.
MOV BP,SI ;Save start.
NEXT_PARA: LODSB
CMP AL,32 ;End of parameter?
JBE END_PARA ;If yes, done here.
CMP AL,"/"
JZ END_PARA
CMP AL,":" ;Drive request?
JNZ NEXT_PARA ;If no, get next byte.
MOV DL,BYTE PTR [SI-2] ;Else, retrieve request.
AND DL,5FH ;Capitalize.
SUB DL,"A" ;Convert to DOS format.
CALL CHANGE_DRIVE ;And change drive.
JMP SHORT NEXT_PARA ;Find end of parameter.
END_PARA: MOV BYTE PTR DS:[SI-1],0 ;Convert parameter to ASCIIZ.
MOV BL,BYTE PTR DS:[SI-2]
GET_WORKING: MOV SI,OFFSET WORKING_DIR ;Store working drive directory.
CALL GET_DIR
CMP BL,":" ;Is there a drive request?
JZ MESSAGE ;If yes, skip directory change.
CMP BL,32 ;Is it a delimiter?
JBE MESSAGE ;If yes, skip.
MOV DX,BP ;Retrieve start.
DEC DX ;Adjust.
CALL CHANGE_DIR ;Change directory.
MOV DX,OFFSET INVALID
JC ERROR_EXIT ;If error, exit.
MESSAGE: CALL CLS ;Clear screen.
CALL CURSOR_OFF ;Cursor off.
MOV SI,OFFSET LOADING ;Display sorting message.
MOV DX,0C19H
CMP SORT_FLAG,1 ;Unless not sorted.
JNZ DISP_MSG
MOV SI,OFFSET LOAD_ONLY ;Then display loading message.
MOV DX,0C1FH
DISP_MSG: CALL DISPLAY_TEXT
MOV DI,OFFSET BUFFER ;Put space character
MOV CX,16000 ; in directory listing
MOV AX,2020H ; buffer.
REP STOSW
;------------------------------------------------------------------;
; Read all the directory filenames and store as records in buffer. ;
;------------------------------------------------------------------;
READ_DIR: MOV DX,OFFSET STAR_DOT_STAR
MOV CX,SEARCH_ATTRIB
CALL FIND_FIRST ;Find first matching file.
JC EXIT ;If empty directory, exit.
STORE_NAME: MOV DI,OFFSET BUFFER + 1 ;Point to buffer.
MOV BP,SP ;Reserve space for stack.
SUB BP,500
CALL BUFFER_NAME ;Convert to directory format.
FIND_NEXT: MOV AH,4FH ;Find next matching.
INT 21H
JC STORE_COUNT ;If carry, no more names.
CALL BUFFER_NAME
CMP DI,BP ;Are we encroaching the stack?
JBE FIND_NEXT ;If no, find next.
MOV DX,OFFSET TOO_MANY ;Else, exit with message.
;-----------------------------------------------------------------------;
; This is the exit routine. Restore the defaults the way we found them. ;
;-----------------------------------------------------------------------;
ERROR_EXIT: MOV AH,9 ;Display error message.
INT 21H
MOV AL,1 ;Error code of one.
JMP SHORT TERMINATE
EXIT: CALL CLS ;Clear screen.
XOR DX,DX ;Set cursor top left.
CALL SET_CURSOR
CALL CURSOR_ON ;Turn cursor back on.
XOR AL,AL ;Error code of zero.
TERMINATE: PUSH AX
MOV AL,CUR_VERIFY ;Restore verify state.
CALL SET_VERIFY
MOV DL,CURRENT_DISK ;Restore drive.
CALL CHANGE_DRIVE
POP AX
MOV AH,4CH
INT 21H
;-----------------------------------;
; Store buffer end address and page ;
; end then sort the filenames. ;
;-----------------------------------;
STORE_COUNT: DEC DI
MOV END_OFFSET,DI ;Store ending offset.
MOV BX,COUNT ;Retrieve file count.
CMP BX,21 ;Enough to fill one page?
JAE DO_SORT ;If yes, use default setting.
MOV AX,160 ;Calculate last record.
MUL BL
ADD AX,BAR_START ;Add bar offset.
MOV PAGE_END,AX
DO_SORT: CMP SORT_FLAG,1 ;Should we sort or leave original?
JZ READY ;If it was "/O", don't sort.
CALL SORT
;------------------------------------------------------------------------;
; Now, we are ready to get target directory and display it and the menu. ;
;------------------------------------------------------------------------;
READY: MOV DI,OFFSET PURGE_DIR ;Point to storage.
CALL GET_DRIVE ;Get drive.
MOV PURGE_DISK,AL
ADD AL,"A" ;Convert to ASCII.
STOSB
MOV AL,":" ;Add colon.
STOSB
MOV SI,DI ;Get directory.
CALL GET_DIR
MOV SI,OFFSET PURGE_DIR ;Make a carbon copy of
MOV DI,OFFSET SOURCE ; directory.
CARBON_COPY: MOVSB
CMP BYTE PTR [SI],0
JNZ CARBON_COPY
MOV AL,"\" ;Add "\" to end of path
CMP [DI-1],AL ; if not root directory.
JZ STORE_END
STOSB
STORE_END: MOV FILE_NAME,DI ;Store end of path to tack
CALL UPDATE_FREE ; on filename later on.
MOV DX,OFFSET WORKING_DIR ;Restore the working directory.
CALL CHANGE_DIR
MOV DL,CURRENT_DISK ;Restore to default drive
CALL CHANGE_DRIVE
MOV DX,OFFSET CURRENT_DIR ; and default directory.
CALL CHANGE_DIR
CALL REFRESH_DIR ;Display drive, directory, menu.
;-----------------------------------------;
; We are ready for business now. We will ;
; loop here, waiting for user keystrokes. ;
;-----------------------------------------;
GET_KEY: CALL UPDATE_SCREEN
CALL READ_KEY ;Get a keystroke.
MOV BX,AX ;Save returned key.
CMP AH,1 ;Is it Esc or below?
JBE FUNCTION ;If yes, function.
CMP AH,36H ;Is it right shift or above?
JAE FUNCTION ;If yes, function.
CMP AH,1CH ;Is it CR?
JZ FUNCTION ;If yes, function.
MOV AH,2 ;Get shift state.
INT 16H
TEST AL,4 ;Is Ctrl depressed?
JNZ FUNCTION ;If no, check function request.
CALL SEARCH ;Else, search for first letter.
JMP SHORT GET_KEY
FUNCTION: MOV DI,OFFSET DISPATCH_KEY
MOV AL,BH
MOV CX,DISPATCH_CNT ;Valid commands.
REPNZ SCASB
JNZ GET_KEY ;If no match, get another.
MOV DI,OFFSET DISPATCH_END
SHL CX,1
SUB DI,CX
CALL DS:[DI] ;Else do subroutine.
JMP SHORT GET_KEY ;Update screen; get next command.
;*************;
; SUBROUTINES ;
;*************;
;---------------------------------------------------------------;
; This subroutine copies either the highlighted or marked file. ;
;---------------------------------------------------------------;
COPY: CALL COUNT_MARKS ;Count marks.
CMP CX,0 ;Any marked files?
JNZ COPY_DEST ;If yes, display "Copy" message.
CALL GET_NAME ;Is the highlighted a directory?
JC COPY_ERROR ;If yes, exit.
COPY_DEST: MOV DX,172FH
MOV SI,OFFSET COPY_MSG
CALL DISPLAY_TEXT
CALL DESTINATION ;Ask user for destination.
JC END_COPY ;If Esc pressed, exit.
MOV COPY_FLAG,1 ;Else, indicate copy.
CALL EXEC_MARKED ;Execute the command.
MOV COPY_FLAG,0 ;Restore copy flag.
END_COPY: RET
COPY_ERROR: CALL BEEP
RET
;----------------------------------------------------------------;
; This subroutine deletes either the highlighted or marked file. ;
;----------------------------------------------------------------;
DELETE: MOV DX,172FH ;Postion cursor for display.
CALL SET_CURSOR
CALL COUNT_MARKS ;Get count of marked files.
CMP CX,0 ;Any marked?
JNZ DELETE_MARKED ;If marked, display number marked.
CALL GET_NAME ;Else get highlighted.
JC DELETE_ERROR ;If it's a directory exit.
CMP BYTE PTR [SI+39],"H" ;If it's a hidden file exit.
JZ DELETE_ERROR
MOV SI,FILE_NAME ;Else display filename.
JMP SHORT DISP_DELETE
DELETE_MARKED: MOV AX,CX ;Display count of marked files.
CALL GET_COUNT
MOV SI,OFFSET MARKED_MSG ;Display "marked files".
DISP_DELETE: CALL GET_TEXT
MOV SI,OFFSET DELETE_MSG ;Display "will be deleted".
CALL GET_TEXT
MOV DX,182FH ;Display warning message.
CALL DISPLAY_TEXT
QUERY: CALL READ_KEY ;Get a keystroke.
CMP AH,31H ;Is it "N"?
JZ DELETE_END ;If yes, exit delete.
CMP AH,1 ;Is it Esc?
JZ DELETE_END ;If yes, exit delete.
CMP AH,15H ;Is it "Y"?
JZ DELETE_FILE ;If yes, delete
CALL BEEP ;Else, beep.
JMP SHORT QUERY ;And get another keystroke.
DELETE_FILE: MOV DELETE_FLAG,1 ;Indicate deletion.
CALL EXEC_MARKED ;Execute the command.
MOV DELETE_FLAG,0 ;Restore deletion flag.
DELETE_END: CALL CLEAR_MSG
RET
DELETE_ERROR: CALL BEEP ;Beep if error.
RET
;--------------------------------------------------------------;
; This subroutine moves either the highlighted or marked file. ;
;--------------------------------------------------------------;
MOVE: CALL COUNT_MARKS ;Get count of marked files.
CMP CX,0 ;Any files marked?
JNZ MOVE_DEST ;If yes, display message.
CALL GET_NAME ;Else, see if highlighted is a
JC MOVE_ERROR ; directory; If yes, exit.
MOVE_DEST: MOV DX,172FH
MOV SI,OFFSET MOVE_MSG ;Display move message.
CALL DISPLAY_TEXT
CALL DESTINATION ;Get user response.
JC END_MOVE ;If Esc pressed, exit.
MOV AL,CURRENT_DISK ;Else, check if move across drives.
ADD AL,"A" ;Get default drive.
CMP BYTE PTR ENTRY + 1,":" ;Is there a drive specified?
JNZ CK_DRIVE ;If not, use default.
MOV AL,ENTRY ;Else, use user drive.
AND AL,5FH ;Capitalize.
CK_DRIVE: CMP AL,SOURCE ;Is it the same as source?
JZ JUST_RENAME ;If yes, rename.
COPY_DELETE: MOV COPY_FLAG,1 ;Else, indicate both copy/delete.
MOV DELETE_FLAG,1
JUST_RENAME: MOV RENAME_FLAG,1
EXEC_MOVE: CALL EXEC_MARKED ;Execute the command.
MOV DELETE_FLAG,0 ;Restore all flags.
MOV COPY_FLAG,0
MOV RENAME_FLAG,0
END_MOVE: RET
MOVE_ERROR: CALL BEEP
RET
;-----------------------------------;
; This subroutine clears all marks. ;
;-----------------------------------;
CLEAR_MARK: MOV SI,OFFSET BUFFER ;Point to start of listing.
NEXT_CLEAR: MOV BYTE PTR [SI],32 ;Write space over mark.
ADD SI,FIELD_SIZE ;Next record.
CMP SI,END_OFFSET ;End of listing?
JB NEXT_CLEAR ;If no, continue until done.
RET
;----------------------------------------------------------------------;
; This subroutine marks all files that aren't marked with an asterisk. ;
;----------------------------------------------------------------------;
MARK_BLANK: MOV SI,OFFSET BUFFER ;Point to start of listing.
NEXT_BLANK: CMP BYTE PTR [SI+14],"<" ;Is it a directory?
JZ LOOP_MARK ;If yes, skip.
CMP BYTE PTR [SI+40],"H" ;Is it a hidden file?
JZ LOOP_MARK ;If yes, skip.
CMP BYTE PTR [SI],32 ;Is it blank (a space)?
JNZ LOOP_MARK ;If no, skip.
MOV BYTE PTR [SI],COPY_MARK ;Else mark.
LOOP_MARK: ADD SI,FIELD_SIZE ;Next record.
CMP SI,END_OFFSET ;Continue until done.
JB NEXT_BLANK
RET
;--------------------------------------------------------;
; This subroutine marks or unmarks the highlighted file. ;
;--------------------------------------------------------;
MARK: MOV DL,COPY_MARK ;Right arrow character.
JMP SHORT STORE_MARK
UNMARK: MOV DL,32 ;Space character.
STORE_MARK: CALL GET_NAME ;Get filename.
JC MARK_END ;If directory, skip.
CMP BYTE PTR [SI+39],"H" ;Is it a hidden file?
JZ MARK_END ;If yes, skip.
MOV [SI-1],DL ;Else store the character.
MARK_END: CALL DN_ARROW ;And move down a row.
RET
;------------------------------------------------;
; This subroutine toggles the copy verify state. ;
;------------------------------------------------;
VERIFY: XOR VERIFY_FLAG,1 ;Toggle flag.
MOV DI,OFFSET MENU+(10*22)+16 ;Point to menu.
MOV SI,OFFSET ON ;Assume "ON".
MOV AL,1
CMP VERIFY_FLAG,1 ;Is it on?
JZ TOGGLE ;If yes, store.
MOV SI,OFFSET OFF ;Else, store "OFF".
XOR AL,AL
TOGGLE: MOV CX,3
REP MOVSB
CALL SET_VERIFY
CALL REFRESH_MENU ;Display.
RET
;----------------------------------------------------;
; This subroutine counts the number of marked files. ;
;----------------------------------------------------;
COUNT_MARKS: XOR CX,CX ;Zero out counter.
MOV SI,OFFSET BUFFER ;Point to start of listing.
NEXT_COPY: CMP BYTE PTR [SI],COPY_MARK ;Is it marked?
JNZ LOOP_COPY ;In no, skip.
INC CX ;Else, increment counter.
LOOP_COPY: ADD SI,FIELD_SIZE ;Next record.
CMP SI,END_OFFSET ;Continue until done.
JB NEXT_COPY
MOV MARK_CNT,CX ;Store the count of marked files.
RET
;---------------------------------------------;
; This subroutine prompts the user for the ;
; destination of highlighted or marked files. ;
;---------------------------------------------;
DESTINATION: CALL GET_NAME ;Get filename.
MOV SI,FILE_NAME
MOV AX,MARK_CNT ;Retrieve count of marked files.
CMP AX,0 ;Were there any?
JZ DISP_SOURCE ;If no, display source filename.
CALL GET_COUNT ;Else, display count of marked.
MOV SI,OFFSET MARKED_MSG ;Display "marked files".
DISP_SOURCE: CALL GET_TEXT
MOV SI,OFFSET TO_MSG ;Display "to..."
CALL GET_TEXT
MOV DX,182FH
CALL CLEAR_OLD ;Remove last user entry.
GET_DEST: CALL READ_KEY ;Get a keystroke.
CMP AL,27 ;Is it Esc?
JZ ABORT_DEST ;If yes, abort.
CMP AL,13 ;Is it carriage return?
JZ DO_DEST ;If yes, execute.
CMP AL,8 ;Is it backspace?
JNZ NOT_BS3 ;If yes, backspace.
CALL MOVE_BS
JMP SHORT GET_DEST
NOT_BS3: CMP AL,32 ;Is it above space?
JBE GET_DEST ;If no, ignore.
CMP DI,OFFSET ENTRY + 32 ;Else, is 32 line entry field full?
JZ GET_DEST ;If yes, ignore.
STOSB ;Else, store the character.
CALL WRITE_TEXT ;And display it.
JMP SHORT GET_DEST
ABORT_DEST: CALL CURSOR_OFF
CALL CLEAR_MSG
STC
RET
DO_DEST: CLC
RET
;------------------------------------------------------------------------------;
; This subroutine either copies moves or deletes a highlighted or marked file. ;
;------------------------------------------------------------------------------;
EXEC_MARKED: CALL CURSOR_OFF ;Turn cursor off.
CMP MARK_CNT,0 ;Are there any files marked?
JNZ MANY_MARKS ;If yes, go find them.
MOV MARK_CNT,1 ;Else, change loop counter to one.
CALL GET_NAME
JMP SHORT EXEC_BAR ;And execute it one time.
MANY_MARKS: CALL HOME_BAR ;Home the highlight bar.
CK_MARK: CALL UPDATE_SCREEN ;Update the screen.
CALL GET_NAME ;Get the highlighted filename.
CMP BYTE PTR [SI-1],COPY_MARK ;Is it marked?
JZ EXEC_BAR ;If yes, execute command.
CALL DN_ARROW ;Else, move down a row.
JMP SHORT CK_MARK ;And check it for a mark.
EXEC_BAR: CMP BYTE PTR [SI+39],"H" ;Is it a hidden file?
JZ EXEC_ERROR ;If yes, skip.
CMP RENAME_FLAG,1 ;Is it a same drive move?
JNZ CK_COPY ;If no, skip renaming.
CALL PARSE_ENTRY ;Else, parse user entry.
MOV DX,OFFSET TARGET ;Point to target.
MOV CX,7 ;Does the file exist?
CALL FIND_FIRST
JNC EXEC_ERROR ;If yes, skip
CMP COPY_FLAG,1 ;Is it across drives?
JZ GO_READ_WRITE ;Is yes copy/delete.
MOV DX,OFFSET SOURCE
MOV DI,OFFSET TARGET
MOV AH,56H ;Else, rename it.
INT 21H
JC EXEC_ERROR ;Next one if failed.
JMP SHORT REMOVE ;Else, remove it from list.
CK_COPY: CMP COPY_FLAG,1 ;Is it a copy request?
JNZ CK_DELETE ;If no, check delete.
CALL PARSE_ENTRY ;Else parse user entry.
GO_READ_WRITE: CALL READ_WRITE ;Copy the file.
JC EXEC_ERROR ;If failed, skip rest.
MARK_IT: MOV SI,CUR_FILE ;Else, mark with asterisk
MOV BYTE PTR [SI-1],"*"
CK_DELETE: CMP DELETE_FLAG,1 ;Is it a delete request?
JNZ CK_KEYSTROKE ;If no, skip.
MOV DX,OFFSET SOURCE ;Else, delete the file.
MOV AH,41H
INT 21H
JC EXEC_ERROR
REMOVE: CALL REMOVE_FILE ;If successful, remove from list.
JMP SHORT CK_KEYSTROKE
EXEC_ERROR: CALL BEEP
CALL DN_ARROW ;Go to next line.
CK_KEYSTROKE: CALL CK_KEY ;Was a key struck while busy
JNZ CLEAR_KEY ; at our copy, move or delete task?
DEC MARK_CNT ;If yes, abort, else all done?
JZ END_EXEC ;If no, continue until done.
JMP CK_MARK
CLEAR_KEY: CALL READ_KEY ;Clear the keyboard buffer,
CALL CK_KEY ; user entry and prompt.
JNZ CLEAR_KEY
END_EXEC: CALL UPDATE_FREE
CALL FILE_COUNT
CALL CLEAR_MSG
RET
;----------------------------------------;
; This subroutine parses the user entry. ;
;----------------------------------------;
PARSE_ENTRY: MOV BP,OFFSET TARGET ;Point to target storage.
MOV DI,BP
MOV SI,OFFSET ENTRY ;Point to user entry.
CMP BYTE PTR [SI],0 ;Anything entered?
JNZ GET_END ;If yes, continue.
JMP TACK_FILENAME ;Else, store source name.
GET_END: LODSB ;Move user entry into target
STOSB ; workspace.
CMP AL,0
JNZ GET_END
STD ;Reverse string operation.
DEC DI ;Adjust pointer back one.
MOV SI,DI ;Make it the source pointer.
MOV FILENAME_END,DI ;And store.
FIND_PATH: CMP SI,OFFSET TARGET - 1 ;Are we at start of name?
JZ SEARCH_WILD ;If yes, done here.
LODSB
CMP AL,"\" ;Else, is it a path delimiter?
JZ FOUND_PATH ;If yes, mark start of filename.
CMP AL,":" ;Colon is also a path delimiter.
JNZ FIND_PATH
FOUND_PATH: INC SI ;Adjust pointer to end of path.
SEARCH_WILD: INC SI
MOV BP,SI ;And store.
CLD ;String back to forward.
MOV DI,FCB ;Use file control block for
MOV AX,2900H ; workspace.
INT 21H ;Parse the entry for globals.
CMP AL,1 ;Any wild cards?
JNZ CK_PATH ;If no, check if it's a directory.
MOV SI,FCB + 1 ;Else, point to first character.
MOV DI,BP ;Point to target storage.
MOV BX,FILE_NAME ;Point to source.
MOV CX,8 ;Eight characters.
GLOBAL_NAME: LODSB
CMP AL,32 ;End of name?
JZ EXTENSION ;If yes, do extension.
CMP AL,"?" ;Wild card?
JNZ LOOP_NAME ;If no, store target character.
MOV AL,[BX] ;Else, replace with source char.
CMP AL,"." ;Unless end of name.
JZ EXTENSION
CMP AL,0
JZ EXTENSION
LOOP_NAME: STOSB ;Store the character.
CMP BYTE PTR [BX],"." ;Are we at end of source name?
JZ NEXT_GLOBAL ;If yes, don't move pointer.
INC BX ;Else, point to next source char.
NEXT_GLOBAL: LOOP GLOBAL_NAME
EXTENSION: MOV AL,"." ;Filename delimiter.
STOSB ;Store it.
FIND_EXT: CMP [BX],AL ;Was there a dot in source?
JZ DO_DOT ;If yes do extension.
CMP BYTE PTR [BX],0 ;End of source name?
JZ DO_EXT ;If yes, do extension.
INC BX ;Else, go to end of name.
JMP SHORT FIND_EXT
DO_DOT: INC BX ;Bump pointer past dot.
DO_EXT: MOV SI,FCB + 9 ;Point to extension of parsed.
MOV CX,3 ;Three characters.
DO_EXTENSION: LODSB
CMP AL,32 ;End of parsed?
JZ END_GLOBAL ;If yes, done here.
CMP AL,"?" ;Wild card?
JNZ LOOP_EXT ;If no, store user character.
MOV AL,[BX] ;Else, store source character.
LOOP_EXT: STOSB
INC BX
LOOP DO_EXTENSION ;Do all three extension chars.
END_GLOBAL: XOR AL,AL ;Make it an ASCIIZ.
STOSB
JMP SHORT PARSE_END ;Done here.
CK_PATH: MOV DI,BP ;Any characters after path
CMP BP,FILENAME_END ; delimiter?
JZ TACK_FILENAME ;If no, tack on source name.
MOV DX,OFFSET ENTRY ;Else, see if it's a directory.
MOV CX,10H
CALL FIND_FIRST
JC PARSE_END ;If not found, done here.
CMP DS:[149],CL ;If not directory, done here.
JNZ PARSE_END
MOV DI,FILENAME_END ;Else, tack on source filename.
MOV AL,"\"
STOSB
TACK_FILENAME: MOV SI,FILE_NAME ;Source filename.
MOV CX,7
REP MOVSW
PARSE_END: RET
;----------------------------------------------------;
; This section does the reading and writing to disk. ;
;----------------------------------------------------;
READ_WRITE: MOV DX,OFFSET SOURCE ;Point to source filespec.
XOR AL,AL ;Open file for reading.
CALL OPEN_FILE
JNC SAVE_HANDLE
JMP END_RW ;Exit if failed.
SAVE_HANDLE: MOV READ_HANDLE,AX ;Save the handle.
MOV CX,7
CALL FIND_FIRST ;Get source
MOV SI,149
LODSB
XOR AH,AH
MOV SOURCE_ATTRIB,AX ; attribute
LODSW
MOV SOURCE_TIME,AX ; time
LODSW
MOV SOURCE_DATE,AX ; date
LODSW
MOV SIZE_LOW,AX ; and size
LODSW
MOV SIZE_HIGH,AX ; and save.
MOV DX,OFFSET TARGET ;Point to target filename.
CALL FIND_FIRST ;Does it exist?
JNC CK_IF_SAME ;If yes, see if same as source.
CALL GET_DISK ;Else, get disk free space.
JMP SHORT CK_FREE ;Go see if enough room.
CK_IF_SAME: MOV CL,DS:[149] ;Get attribute of target
XOR CH,CH
MOV BP,CX ; and save.
XOR CX,1 ;Flip read-only attribute.
CALL CHMOD
MOV DX,OFFSET SOURCE ;Now get source attribute.
CALL GETMOD
CMP CX,SOURCE_ATTRIB ;See if it has changed.
PUSHF ;Save compare results.
MOV DX,OFFSET TARGET ;Restore target attribute.
MOV CX,BP
CALL CHMOD
POPF ;Retrieve compare results.
STC ;Assume files are the same.
JNZ CLOSE_READ ;If they are, exit.
CALL GET_DISK ;Else, get free disk space.
ADD AX,DS:[154]
ADC DX,DS:[156] ;Target size + disk free.
CK_FREE: SUB AX,SIZE_LOW ;Total - source size.
SBB DX,SIZE_HIGH
JB CLOSE_READ ;If negative, not enough room.
CREATE: MOV DX,OFFSET TARGET ;Create and truncate target file
XOR CX,CX ; to zero.
MOV AH,3CH
INT 21H
JC CLOSE_READ
MOV WRITE_HANDLE,AX ;Save handle.
MOV AX,DS ;Point to second 64K segment
ADD AX,1000H ; for read/write buffer.
MOV DS,AX
XOR DX,DX
COPY_READ: MOV BX,CS:READ_HANDLE ;Retrieve read handle.
MOV CX,0FFFFH ;Read up to 64K at a time.
MOV AH,3FH
INT 21H
JC COPY_DONE ;If done, exit.
CMP AX,0 ;If zero, also done.
JZ CHANGE_DATE
MOV BP,AX ;Save bytes read.
MOV CX,AX ;Bytes read into counter.
MOV BX,CS:WRITE_HANDLE ;Retrieve write handle.
MOV AH,40H
INT 21H ;Write the buffer to disk.
JC COPY_DONE
CMP CX,BP ;Did we write same number as read?
STC ;Assume we had a problem.
JNZ COPY_DONE ;If no, exit.
CMP CX,0FFFFH ;Was it a full 64K read?
JZ COPY_READ ;If yes, there must be more.
CHANGE_DATE: MOV BX,CS:WRITE_HANDLE
MOV CX,CS:SOURCE_TIME ;Else, make time/date same
MOV DX,CS:SOURCE_DATE ; as source.
MOV AX,5701H
INT 21H
COPY_DONE: PUSH CS ;Restore data segment.
POP DS
CLOSE_WRITE: PUSHF ;Save error if any.
MOV BX,WRITE_HANDLE ;Close write file.
CALL CLOSE_FILE
POP AX ;Retrieve flags.
JC CLOSE_READ ;Close successful?
XCHG AH,AL ;If no, exit with error, else
SAHF ; retrieve write state.
CLOSE_READ: PUSHF ;Save flags.
MOV BX,READ_HANDLE ;Close read file.
CALL CLOSE_FILE ;Return with status of
POPF ; write file.
END_RW: RET
;------------------------------------------------------------------------;
; These four subroutines control in which column the sorting will start. ;
;------------------------------------------------------------------------;
SORT_NAME: MOV SORT_OFFSET,0
JMP SHORT SORT_MSG
SORT_EXT: MOV SORT_OFFSET,4
JMP SHORT SORT_MSG
SORT_SIZE: MOV SORT_OFFSET,8
JMP SHORT SORT_MSG
SORT_DATE: MOV SORT_OFFSET,12
SORT_MSG: MOV DX,1733H
MOV SI,OFFSET LOADING+12
CALL DISPLAY_TEXT
;------------------------------------------;
; This subroutine does the actual sorting. ;
;------------------------------------------;
SORT: CMP COUNT,1 ;Can't sort one file.
JZ SORT_RETURN
MOV DX,END_OFFSET ;End of filenames in DX.
SUB DX,44
MOV BP,SORT_OFFSET
NEXT_PASS: MOV SORT_FLAG,0
MOV BX,OFFSET BUFFER + 1 ;Point to start of buffer.
NEXT_SORT: MOV SI,BX ;Source and destination.
ADD SI,SORT_TABLE[BP]
MOV DI,SI
ADD DI,FIELD_SIZE
CMP BP,12 ;Is it special case of date?
JZ DO_DATE ;If yes, go do it.
MOV CX,SORT_TABLE[BP+2]
COMPARE: REPZ CMPSB ;Compare filenames.
JBE END_SORT ;If already in order, skip.
SWAP: MOV SI,BX ;Else, recover pointers.
DEC SI
MOV DI,SI
ADD DI,FIELD_SIZE
MOV CX,FIELD_SIZE / 2 ;Exchange the records.
NEXT_SWAP: MOV AX,[DI]
MOVSW
MOV [SI-2],AX
LOOP NEXT_SWAP
MOV SORT_FLAG,1 ;Flag that exchange was made.
END_SORT: ADD BX,FIELD_SIZE ;Point to next record.
CMP BX,DX ;End of top?
JB NEXT_SORT ;If no, bubble sort next.
SUB DX,FIELD_SIZE ;Else, move top down one record.
CMP SORT_FLAG,0 ;Was there exchange made?
JNZ NEXT_PASS ;If yes, another pass.
SORT_RETURN: CALL CLEAR_MSG
RET
DO_DATE: MOV CX,2 ;Compare year first.
REPZ CMPSB
JA SWAP ;If above, swap.
JNZ END_SORT
SUB SI,8 ;Else, adjust and do month/day.
SUB DI,8
MOV CX,5
REPZ CMPSB
JA SWAP ;If above, swap.
JNZ END_SORT
ADD SI,10 ;Else, adjust and do meridian.
ADD DI,10
CMPSB
JA SWAP ;If above, swap.
JNZ END_SORT
SUB SI,6 ;Else, adjust and do time.
SUB DI,6
MOV CX,5
CMP WORD PTR [SI],3231H ;Is it special case "12:"?
JZ CK_MERIDIAN ;If yes, see if same.
CMP WORD PTR [DI],3231H ;Is destination "12:"?
JNZ COMPARE ;If no, normal compare.
JMP SWAP ;Else, swap.
CK_MERIDIAN: CMPSW ;Are both "12:"?
JNZ END_SORT ;If no, next record.
MOV CX,3 ;Else compare minutes.
JMP SHORT COMPARE
;--------------------------------------------------------------------------;
; These six subroutines control the bar and page of the directory listing. ;
;--------------------------------------------------------------------------;
UP_ARROW: MOV BP,-160 ;Move bar up one line.
JMP SHORT BAR_MOVE
DN_ARROW: MOV BP,160 ;Move bar down one line.
BAR_MOVE: CALL SCROLL_BAR
RET
PG_UP: MOV BP,- FIELD_SIZE * 21 ;Move up 21 lines.
CALL SCROLL
JMP SHORT BOTTOM_BAR
PG_DN: MOV BP,FIELD_SIZE * 21 ;Move down 21 lines.
MOVE_PAGE: CALL SCROLL
JMP SHORT TOP_BAR ;Move bar to top.
HOME_BAR: MOV CUR_OFFSET,OFFSET BUFFER ;Move listing to beginning.
TOP_BAR: MOV SI,BAR_START ;And move bar to top.
CALL MOVE_BAR
RET
END_BAR: MOV BX,END_OFFSET ;Move listing to last page.
SUB BX,21 * FIELD_SIZE
CMP BX,OFFSET BUFFER
JBE BOTTOM_BAR
MOV CUR_OFFSET,BX
BOTTOM_BAR: MOV SI,PAGE_END ;And move bar to bottom.
SUB SI,160
CALL MOVE_BAR
RET
;-----------------------------------------------------------------------;
; This subroutine searches for a filename with a specific first letter. ;
;-----------------------------------------------------------------------;
SEARCH: CMP BL,"a" ;Capitalize if lower case.
JB SEARCH_IT
CMP BL,"z"
JA SEARCH_IT
AND BL,5FH
SEARCH_IT: CALL GET_NAME ;Get current position.
XOR DX,DX ;Zero out file counter.
MOV DI,SI ;Store current position in DI.
MOV SI,OFFSET BUFFER + 1 ;Point to top of listing.
CMP BYTE PTR [DI],BL ;Are we currently at a match?
JNZ NEXT_SEARCH ;If no, start from top.
FIND_START: INC DX ;Increment count.
ADD SI,FIELD_SIZE ;Increment record.
CMP SI,DI ;New record?
JBE FIND_START ;If no, find it.
NEXT_SEARCH: CMP BYTE PTR [SI],BL ;Got a match?
JZ FOUND_IT ;If yes, process.
INC_SEARCH: ADD SI,FIELD_SIZE ;Else, point to next record.
INC DX
CMP BYTE PTR [SI],32 ;End of listing?
JNZ NEXT_SEARCH ;If no, keep searching.
CALL BEEP ;No matches, so beep.
RET
FOUND_IT: MOV CX,COUNT ;Retrieve file count.
SUB CX,DX ;Subtract search count.
MOV SEARCH_COUNT,CX ;And store.
MOV CL,NORMAL ;Turn off bar for now.
MOV BAR_ATTRIBUTE,CL
CALL END_BAR ;First move to end.
JMP SHORT FIND_IT
NEXT_FIND: CALL UP_ARROW ;Move up to matching filename.
FIND_IT: DEC SEARCH_COUNT
JNZ NEXT_FIND
MOV CL,INVERSE ;Turn bar back on and display.
MOV BAR_ATTRIBUTE,CL
XOR BP,BP
CALL SCROLL_BAR
RET
;--------------------------------------------------------------------------;
; This subroutine gets the highlighted file and converts it to DOS format. ;
;--------------------------------------------------------------------------;
GET_NAME: MOV SI,CUR_OFFSET ;Get top of page.
INC SI ;Bump past mark field.
MOV AX,LINE ;Get location of bar.
SUB AX,BAR_START ;Adjust.
MOV CL,160 ;Convert to byte pointer.
DIV CL
MOV CL,FIELD_SIZE
MUL CL
ADD SI,AX ;Add to current offset.
MOV CUR_FILE,SI ;And save pointer.
PUSH SI
MOV DI,FILE_NAME ;Store the first eight characters.
MOV CX,8
CALL STORE_BYTES
INC SI
CMP BYTE PTR DS:[SI],32 ;End of name?
JZ END_NAME ;If yes, done here.
MOV AL,"." ;Else, add dot.
STOSB
MOV CX,3 ;Three possible characters
CALL STORE_BYTES ; as extension.
END_NAME: MOV BYTE PTR [DI],0 ;Convert to ASCIIZ.
POP SI
CMP BYTE PTR [SI+13],"<" ;Is it a directory?
STC
JZ NAME_ERROR ;If yes, indicate so.
CLC
NAME_ERROR: RET
STORE_BYTES: LODSB ;Get a character.
CMP AL,32 ;If it's space, skip.
JZ SKIP_STORE
STOSB
SKIP_STORE: LOOP STORE_BYTES
RET
;-----------------------------------------------------------;
; This subroutine moves and turns the cursor on and removes ;
; the last user entry in preparation for new input. ;
;-----------------------------------------------------------;
CLEAR_OLD: CALL SET_CURSOR ;Move cursor.
CALL CURSOR_ON ;Turn it on.
MOV DI,OFFSET ENTRY ;Write nulls over old entry.
XOR AX,AX
MOV CX,18
REP STOSW
MOV DI,OFFSET ENTRY ;Initiate pointer for entry.
RET
;-----------------------------;
; This subroutine backspaces. ;
;-----------------------------;
MOVE_BS: CMP DI,OFFSET ENTRY ;At beginning of field?
JZ MOVE_BS_END ;If yes, skip.
DEC DI ;Else, decrement pointer.
MOV BYTE PTR [DI],0
MOV SI,OFFSET BS ;Erase last character.
CALL GET_TEXT
MOVE_BS_END: RET
;------------------------------------------------------------------;
; This subroutine removes the filename from the directory listing. ;
;------------------------------------------------------------------;
REMOVE_FILE: MOV DI,CUR_FILE ;Point to filename.
DEC DI ;Include mark field.
MOV SI,DI ;Move all the records
ADD SI,FIELD_SIZE ; that follow up one.
NEXT_RECORD: MOV CX,FIELD_SIZE / 2
REP MOVSW
CMP DI,END_OFFSET
JB NEXT_RECORD
SUB DI,FIELD_SIZE
MOV END_OFFSET,DI ;Store new end.
XOR BP,BP
CALL SCROLL ;Update the screen.
DEC COUNT
DEC FILE_CNT ;Decrement file count.
JNZ MORE_FILES ;If empty, exit.
JMP EXIT
MORE_FILES: CMP COUNT,21 ;Full page?
JAE REMOVE_END ;If yes, skip.
SUB PAGE_END,160 ;Else, adjust page end.
MOV SI,PAGE_END
SUB SI,160
CMP SI,LINE ;Is bar below directory listing?
JA REMOVE_END ;If no, skip.
CALL MOVE_BAR ;Else, move bar up one line.
REMOVE_END: RET
;----------------------------------------------;
; This subroutine displays the count of files. ;
;----------------------------------------------;
FILE_COUNT: MOV DI,OFFSET FILES ;Blank out previous count.
MOV AX,2020H
STOSW
MOV AX,FILE_CNT
XOR DX,DX
CALL TRANSLATE
DISPLAY_BYTES: MOV DX,1806H ;Row 24; column 6.
MOV SI,OFFSET FILES ;Display file count.
CALL DISPLAY_TEXT
RET
;---------------------------------------------------;
; This subroutine converts a hex number to decimal. ;
;---------------------------------------------------;
TRANSLATE: XCHG AX,DX
MOV BX,10 ;Convert to decimal.
STD ;Reverse direction.
NEXT_COUNT: MOV CX,DX
XOR DX,DX
DIV BX
XCHG AX,CX
DIV BX
XCHG AX,DX
ADD AL,"0" ;Convert to ASCII.
STOSB ;Store the remainder.
MOV AX,CX
OR CX,DX
JNZ NEXT_COUNT
CLD ;Back to forward direction.
RET
;----------------------------------------------------------------------------;
; This subroutine displays the current directory, menu, and number of files. ;
;----------------------------------------------------------------------------;
REFRESH_DIR: CALL CLS ;Clear the screen.
REFRESH_MENU: MOV SI,OFFSET MENU ;Point to menu position.
MOV DI,(2*160)+98 ;And to screen position.
MOV BH,20 ;Display 20 lines of menu.
NEXT_REFRESH: MOV CX,22 ;22 characters per line.
NEXT_MENU: LODSB
MOV BL,AL
CALL WRITE_SCREEN
LOOP NEXT_MENU
ADD DI,116 ;Next line.
DEC BH
JNZ NEXT_REFRESH
MOV DX,4
MOV SI,OFFSET DIRECTORY ;Display "Directory ".
CALL DISPLAY_TEXT
MOV SI,OFFSET PURGE_DIR ;Display working directory.
CALL GET_TEXT
CALL FILE_COUNT ;Display file count.
MOV BL,INVERSE ;Put up cursor bar.
CALL BAR
RET
;-------------------------------------;
; This subroutine scrolls the screen. ;
;-------------------------------------;
SCROLL: MOV SI,CUR_OFFSET ;Get current offset.
ADD SI,BP ;Add requested direction.
CK_LOWER: CMP SI,OFFSET BUFFER ;If above start check upper limit.
JAE UPPER_LIMIT
LOWER_LIMIT: MOV CUR_OFFSET,OFFSET BUFFER ;Else, make it start.
JMP SHORT SCROLL_RETURN ;And update screen.
UPPER_LIMIT: MOV BX,END_OFFSET ;See if beyond end of
CMP BX,OFFSET BUFFER + 21 * FIELD_SIZE ; directory listing.
JA CK_UPPER
MOV CUR_OFFSET,OFFSET BUFFER
JMP SHORT SCROLL_RETURN
CK_UPPER: SUB BX,21 * FIELD_SIZE
CMP SI,BX
JBE END_SCROLL
MOV SI,BX
END_SCROLL: MOV CUR_OFFSET,SI ;Update current offset.
SCROLL_RETURN: RET
;--------------------------------------------------;
; This subroutine scrolls the bar if between start ;
; and end of page. Otherwise the page is scrolled. ;
;--------------------------------------------------;
SCROLL_BAR: MOV SI,LINE ;Get current line.
ADD SI,BP ;Add requested line.
MOV BP,- FIELD_SIZE ;Assume below beginning.
CMP SI,BAR_START ;Is it?
JB SCROLL_PAGE ;If yes, scroll page instead.
MOV BP,FIELD_SIZE ;Do the same for end of page.
CMP SI,PAGE_END
JAE SCROLL_PAGE
CALL MOVE_BAR
RET
SCROLL_PAGE: CALL SCROLL
RET
;----------------------------------------------------;
; This subroutine does the actual moving of the bar. ;
;----------------------------------------------------;
MOVE_BAR: MOV BL,NORMAL ;Remove old bar.
CALL BAR
MOV LINE,SI ;And move bar to new line.
MOV BL,BAR_ATTRIBUTE
CALL BAR
RET
BAR: MOV DI,LINE ;Retrieve line.
MOV CX,39 ;Bar length 39.
NEXT_BAR: CALL WRITE_SCREEN ;Write the attribute.
LOOP NEXT_BAR
RET
;-------------------------------------------------;
; This subroutine displays the directory listing. ;
;-------------------------------------------------;
UPDATE_SCREEN: XOR BP,BP
MOV SI,CUR_OFFSET ;Retrieve starting offset.
MOV DI,2*160 ;Point to row two of screen.
MOV BH,21 ;21 lines to write.
NEXT_WRITE: MOV CX,FIELD_SIZE ;44 characters per line.
NEXT_CHAR: LODSB ;Get a byte.
MOV BL,AL ;Save it in BL.
CALL WRITE_SCREEN ;Write them.
LOOP NEXT_CHAR
ADD DI,160 - FIELD_SIZE * 2 ;Bump pointer to next line.
DEC BH ;Do all 21 lines.
JNZ NEXT_WRITE
RET
;------------------------------------------------------------;
; This subroutine displays the directory by writing directly ;
; to the screen buffer. To avoid screen noise (snow) on the ;
; color card, the horizontal retrace has to be monitored. ;
;------------------------------------------------------------;
WRITE_SCREEN: MOV DX,STATUS_REG ;Retrieve status register.
MOV AX,VIDEO_SEG ;Point to screen segment.
MOV ES,AX
HORZ_RET: IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET ;If not, wait until it is.
CLI ;No more interrupts.
HWAIT: IN AL,DX ;Get status.
TEST AL,1 ;Is it high?
JZ HWAIT ;If no, wait until it is.
MOV AL,BL ;Retrieve character; now it's OK
STOSB ; to write to screen buffer.
STI ;Interrupts back on.
INC DI ;Bump pointer past attribute.
PUSH CS
POP ES
RET ;Return
;-----------------------------------------------------------------------;
; These two subroutines clear either the messages or the entire screen. ;
;-----------------------------------------------------------------------;
CLEAR_MSG: MOV CX,172CH ;Row 24; column 43.
MOV DX,184FH ;Row 25; column 79.
JMP SHORT CLEAR_WINDOW
CLS: XOR CX,CX
MOV DX,184FH ;Entire screen.
CLEAR_WINDOW: PUSH BP
PUSH BX
MOV BH,NORMAL ;Clear with original attribute.
MOV AX,600H
INT 10H
POP BX
POP BP
RET
;-----------------------------------------;
; These subroutines display the messages. ;
;-----------------------------------------;
DISPLAY_TEXT: CALL SET_CURSOR ;Move cursor.
GET_TEXT: LODSB
CMP AL,0 ;Zero marks end of string.
JZ END_TEXT
CALL WRITE_TEXT
JMP SHORT GET_TEXT
END_TEXT: RET
WRITE_TEXT: PUSH SI ;BIOS does not save SI.
MOV AH,0EH ;Write teletype.
INT 10H
POP SI
RET
;--------------------------------------------------------------;
; These two subroutines change the default drive or directory. ;
;--------------------------------------------------------------;
GET_DRIVE: MOV AH,19H
INT 21H
RET
CHANGE_DRIVE: MOV AH,0EH
INT 21H
RET
;---------------------------------------------;
; These two subroutines open or close a file. ;
;---------------------------------------------;
OPEN_FILE: MOV AH,3DH
INT 21H
RET
CLOSE_FILE: MOV AH,3EH
INT 21H
RET
;------------------------------------------------;
; This subroutine finds the first matching file. ;
;------------------------------------------------;
FIND_FIRST: MOV AH,4EH
INT 21H
RET
;--------------------------------------------------------------;
; These two subroutines retrieve or change a file's attribute. ;
;--------------------------------------------------------------;
CHMOD: MOV AX,4301H
INT 21H
RET
GETMOD: MOV AX,4300H
INT 21H
RET
;---------------------------------------------------------;
; This subroutine gets the free disk space of the target. ;
;---------------------------------------------------------;
GET_DISK: MOV SI,DX ;Retrieve pointer to target file.
MOV DL,-1 ;Assume default drive.
CMP BYTE PTR [SI+1],":" ;Is there a drive request?
JNZ GET_FREE ;If no, get default drive.
MOV DL,[SI] ;Else, retrieve drive request.
AND DL,5FH ;Capitalize.
SUB DL,"A" ;Convert to DOS format.
GET_FREE: CALL DISK_FREE ;Get free bytes.
RET
;--------------------------------------------------------------;
; This subroutine gets the free disk space of the source drive ;
;--------------------------------------------------------------;
UPDATE_FREE: MOV DL,PURGE_DIR ;Get source drive.
SUB DL,"A" ;Convert to DOS format.
CALL DISK_FREE ;Get disk free space.
MOV DI,OFFSET FILES + 20 ;Point to storage.
CALL TRANSLATE ;Convert hex to decimal and store.
RET
;----------------------------------------------;
; This subroutine retrieves available clusters ;
; and converts it to hexidecimal bytes free. ;
;----------------------------------------------;
DISK_FREE: INC DL ;Adjust drive.
MOV AH,36H ;Disk free space.
INT 21H
XOR DX,DX
MUL BX ;Sectors per cluster times clusters
MUL CX ;Result times bytes per cluster.
RET
;------------------------------------------;
; This subroutine converts hex to decimal. ;
;------------------------------------------;
GET_COUNT: MOV BX,10 ;Convert to decimal.
XOR CX,CX ;Zero in counter.
GET_NUMBER: XOR DX,DX ;Zero in high half.
DIV BX
ADD DL,"0" ;Convert to ASCII.
PUSH DX ;Save results.
INC CX ;Also increment count.
CMP AX,0 ;Are we done?
JNZ GET_NUMBER
NEXT_NUMBER: POP AX ;Retrieve numbers.
CALL WRITE_TEXT ;And write them.
LOOP NEXT_NUMBER
RET
;---------------------------------------------------------;
; These five subroutines move the cursor, get the current ;
; directory, beep the speaker, check or get a keystroke. ;
;---------------------------------------------------------;
SET_CURSOR: PUSH SI
XOR BH,BH ;Page zero.
MOV AH,2 ;Set cursor.
INT 10H
POP SI
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 ;Retrieve default directory.
INT 21H
RET
BEEP: MOV DL,7 ;Beep via DOS.
MOV AH,2
INT 21H
RET
READ_KEY: MOV AH,0 ;Retrieve keystroke via BIOS.
INT 16H
RET
CK_KEY: MOV AH,1 ;Check for keystroke via BIOS.
INT 16H
RET
;-------------------------------------------------------------;
; This subroutine waits until a keystroke is pressed and then ;
; clears the message. Keystroke remains in keyboard buffer. ;
;-------------------------------------------------------------;
DELAY: CALL CK_KEY
JZ DELAY
CALL CLEAR_MSG
RET
;-----------------------------------------------;
; These subroutines turn the cursor off and on. ;
;-----------------------------------------------;
CURSOR_OFF: MOV CX,2000H
JMP SHORT SET_TYPE
CURSOR_ON: MOV CX,CURSOR_TYPE
SET_TYPE: MOV AH,1
INT 10H
RET
;------------------------------------------------;
; This subroutine changes the default directory. ;
;------------------------------------------------;
CHANGE_DIR: MOV AH,3BH
INT 21H
RET
;------------------------------------------------;
; This subroutine changes the copy verify state. ;
;------------------------------------------------;
SET_VERIFY: MOV AH,2EH
INT 21H
RET
;--------------------------------------------------;
; This long subroutine stores the filename in DIR ;
; format. That is, filename, bytes, date and time. ;
;--------------------------------------------------;
BUFFER_NAME: MOV SI,158 ;Point to filename.
MOV CX,12 ;Store 12 bytes of filename.
CMP BYTE PTR [SI],"." ;Is it a dot directory?
JNZ INC_COUNT ;If no, it's a file.
CMP BYTE PTR [SI+1],"." ;Is it a double dot directory?
JNZ DONT_STORE ;If no, single dot so skip.
INC COUNT ;Else, increment total count.
LODSB ;Store dots and go to file size.
STOSB
STOSB
ADD DI,10
JMP SHORT FILE_SIZE
DONT_STORE: RET
INC_COUNT: INC COUNT ;Increment total count.
NEXT_STORE: LODSB ;Get a byte.
CMP AL,0 ;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,32
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,32 ;Pad balance with spaces.
REP STOSB
FILE_SIZE: PUSH DI ;Save pointer.
TEST BYTE PTR DS:[149],10H ;Is it a directory?
JZ STORE_SIZE ;If no, store size.
MOV SI,OFFSET DIRECTORIES ;Else, store "<DIR>".
INC DI
MOV CX,5
REP MOVSB
JMP SHORT END_DATE
STORE_SIZE: INC FILE_CNT ;Increment file count.
ADD DI,8 ;Move to end of bytes field.
MOV DX,DS:[156] ;Retrieve high and low words
MOV AX,DS:[154] ; of bytes.
CALL TRANSLATE ;Convert to decimal.
END_DATE: POP DI ;Retrieve pointer.
ADD DI,11 ;Move to date field.
DATE: MOV DX,DS:[152] ;Retrieve date.
MOV AX,DX
MOV CL,5 ;Shift to lowest bits.
ROR AX,CL
AND AX,0FH ;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,1FH ;Mask off all but day.
MOV CL,0 ;Flag include leading zeros.
MOV CH,"-"
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date for last time.
MOV CL,9
ROR AX,CL
AND AX,7FH ;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: MOV CL,0 ;Display leading zeros.
MOV CH,32
CALL STORE_WORD ;Store it.
TIME: INC DI ;Move to time field.
MOV DX,DS:[150] ;Retrieve time.
MOV AX,DX
MOV CL,11 ;Shift to hours bits.
ROR AX,CL
AND AX,1FH ;Mask off all but hours.
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.
ROR AX,CL
AND AX,3FH ;Mask off all but minutes.
MOV CL,0
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.
MOV AH,BYTE PTR DS:[149] ;Get attribute byte.
MOV AL,"H" ;Assume it's hidden.
TEST AH,2 ;Is it?
JNZ HIDDEN ;If yes, store "H".
MOV AL,32 ;Else, store a space.
HIDDEN: STOSB
MOV AL,"S" ;Assume it's system.
TEST AH,4 ;Is it?
JNZ SYSTEM ;If yes, store "S".
MOV AL,32 ;Else, store a space.
SYSTEM: STOSB
MOV AL,"R" ;Assume it's read-only.
TEST AH,1 ;Is it?
JNZ READ_ONLY ;If yes, store "R".
MOV AL,32 ;Else, store a space.
READ_ONLY: STOSB
MOV AL,"A" ;Assume it's archive.
TEST AH,20H ;is it?
JNZ ARCHIVE ;If yes, store "A".
MOV AL,32 ;Else store a space.
ARCHIVE: STOSB
INC DI ;Bump pointer past mark field.
RET
;-------------------------------;
STORE_WORD: MOV BL,10
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,32 ;Else, store a space.
STORE_IT: STOSW
MOV AL,CH ;Store delimiter character also.
STOSB
RET
;-------------------------------------------;
; This is the new Critical Error interrupt. ;
;-------------------------------------------;
DISK_ERROR: STI ;Interrupts back on.
PUSHF ;Save all registers.
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
PUSH DS
PUSH ES
PUSH AX ;Save failed drive number.
MOV AX,CS
MOV DS,AX ;Point to our data segment.
MOV ES,AX
CALL CLEAR_MSG ;Clear current message.
MOV SI,OFFSET DISK_MSG ;Display disk error message.
MOV DX,172FH
CALL DISPLAY_TEXT
POP AX ;Retrieve fail drive and display.
ADD AL,"A"
CALL WRITE_TEXT
MOV DX,182FH ;Display rest of error message.
CALL DISPLAY_TEXT
WAIT_KEY: CALL READ_KEY ;Get a response to message.
CMP AH,13H ;Was it scan code for "R"?
JZ END_DISK ;If yes retry.
CMP AH,10H ;Was it "Q"?
JNZ WAIT_KEY ;If no, wait until correct response
JMP EXIT ;Else, exit to DOS.
END_DISK: CALL CLEAR_MSG ;Clear disk error message.
POP ES ;Restore registers.
POP DS
POP BP
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POPF
MOV AL,1 ;Return with retry request.
IRET
CURRENT_DIR DB 0
WORKING_DIR EQU CURRENT_DIR+68
PURGE_DIR EQU WORKING_DIR+68
SOURCE EQU PURGE_DIR+66
TARGET EQU SOURCE+65+13
ENTRY EQU TARGET+65+13
BUFFER EQU ENTRY+36
CODE ENDS
END START