home *** CD-ROM | disk | FTP | other *** search
- ; RN.ASM
- ; RN [d:][/I] /I option installs resident database
-
- CODE SEGMENT ;*************************
- ASSUME CS:CODE,DS:CODE ;* *
- ORG 100H ;* REMEMBER TO EXE2BIN *
- ;* *
- START: JMP BEGINNING ;*************************
-
- ; DATA AREA
- ; ---------
- INSTALL_MSG DB 'RN sucessfully installed',13,10
- COPYRIGHT DB 'Copyright 1987 Ziff-Davis Publishing Co.',13,10
- PROGRAMMER DB 'Michael J. Mefford$',1AH
- NO_FREE DB 'Too many resident programs$'
- REQUIRES DB 'Requires DOS 2.x$'
- NOT_ENOUGH DB 'Requires 128K free RAM$'
- UNKNOWN DB 'Drive not supported$'
- HEADING DB 'Directories of drive ',0
- DIR_MSG DB ' directories',0
- FILE_COUNT DB ' files in ',0
- USING DB ' using ',0
- LOADING DB 'Loading and sorting directories',13,10,0
- RENAME_MSG DB 'Enter new name for ',0
- PATH_LENGTH DB 'Path length is now ',0
- DB '. Maximum is 63.',0
- MKDIR_MSG DB 'Enter new subdirectory for ',0
- RMDIR_MSG DB 'Warning: All files will be lost.',0
- DB 'Do you still wish to remove it? Y/N ',0
- HIDE_MSG DB 'H to hide or U to unhide ',0
- READ_ONLY_MSG DB 'R to mark read-only U to undo read-only',0
- ARCHIVE_MSG DB 'S to set R to reset archive bit',0
- HAVE_BEEN DB 'have been marked ',0
- DB 'not to be BACKUPed.',0
- READ_MSG DB 'not read-only.',0
- BS DB 8,32,8,0
-
- DATA_INT DB 0
- DATA_SEGMENT DW ?
-
- DOS_VERSION DB ?
- ROOT DB '\ (ROOT)'
- ROOT_DIR DB '\',0
- DOT_DOT DB '..',0
- STAR_DOT_STAR DB '*.*',0
- DEFAULT_DRIVE DB ?
- DRIVE DB ?
- ROOT_SECTORS DW ?
- CLUST_RECORDS DW ?
- CLUST_SECTORS DW ?
- CLUST_BYTES DW ?
- CLUST_COUNT DW ?
- LAST_CLUSTER DW ?
- LAST_ENTRY DW ?
- END_OFFSET DW ?
- STRIP_MASK DB ?
- ADD_MASK DB ?
-
- STATUS_REG DW ?
- VIDEO_SEG DW 0B000H
- NORMAL DB 07H
- INVERSE DB 70H
- BAR_ATTRIBUTE DB 70H
- CURSOR_TYPE DW ?
- CUR_OFFSET DW DIRECTORIES
- CUR_RECORD DW ?
- LINE DW 323
- PAGE_END DW 21*160+323
- DIR_COUNT DW 1
- COUNT DW ?
- BAR_START DW 323
- BAR_LENGTH DW 8
- SEARCH_COUNT DW ?
- DIR_NAME DW ?
-
- COMSPEC DB 'COMSPEC='
- PARAMETER DB 7,'/C DR/O',13
-
- ENVIRONMENT DW ?
- COM_LINE_PTR DD OFFSET PARAMETER
- STACK_SEG DW ?
- STACK_PTR DW ?
-
- DIR_RECORD EQU 40
- DATA_RECORD EQU 20
-
- ROOT_DIRECTORY EQU 0
- FAT EQU ROOT_DIRECTORY
- WORKSPACE EQU 65535-16384
-
- DISPATCH_KEY DB 1,1CH,3BH,3CH,3DH,3EH,3FH,40H,41H,42H,43H
- DB 44H,47H,48H,49H,4FH,50H,51H,76H,84H
-
- DISPATCH_TABLE DW ESC_EXIT, CHANGE_DIR, CHANGE_DIR, RENAME, MKDIR
- DW RMDIR, HIDE_UNHIDE, READ_ONLY, SET_RESET, REREAD
- DW FILE_SUM, DR, HOME_BAR, UP_ARROW, PG_UP
- DW END_BAR, DN_ARROW, PG_DN, BOTTOM_BAR, TOP_BAR
-
- MENU LABEL BYTE
- DB 201,20 DUP (205),187,186,' PC Magazine RN.COM ',186
- DB 186,' (C) Copr. 1987 ZD ',186,186,' Michael J. Mefford ',186
- DB 199,20 DUP (196),182,186,' F1 ChDir (or ',17,196,217,')',186
- DB 186,' F2 Rename ',186,186,' F3 MkDir ',186
- DB 186,' F4 RmDir ',186,186,' F5 Hide/Unhide ',186
- DB 186,' F6 Do/Undo R-O ',186,186,' F7 Set/Reset Arc ',186
- DB 186,' F8 Reread ',186,186,' F9 File count ',186
- DB 186,' F10 DR ',186,186,' Esc to Exit ',186
- DB 200,20 DUP (205),188,' Use: ',24,32,25,' PgUp PgDn '
- DB ' ^PgUp ^PgDn Home End '
-
- ;---------------------------------------------------------------------;
- ; Store our data segment. We will be writing directly to the screen ;
- ; buffer so we need the display card address and the status register. ;
- ;---------------------------------------------------------------------;
-
- ; CODE AREA
- ; ---------
- BEGINNING: CLD ;String moves in forward direction.
- PUSH DS
- POP DATA_SEGMENT ;Store our data segment.
- MOV AX,3301H ;Turn Control Break off.
- MOV DL,0
- INT 21H
-
- 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 ;And save it.
- CALL CURSOR_OFF
-
- ;---------------------------------------------;
- ; Check DOS version and allocate 128K memory. ;
- ;---------------------------------------------;
-
- MOV AH,30H ;Get DOS version.
- INT 21H
- MOV DOS_VERSION,AL ;And save.
- CMP AL,2 ;Is it 2.x or above?
- JAE CONTINUE ;If yes, continue.
-
- MOV DX,OFFSET REQUIRES ;Else, exit with message.
- QUIT: JMP MSG_EXIT
-
- CONTINUE: CMP AL,3 ;Is it DOS 3.x or above?
- JAE RENAME_OK ;If yes continue.
- MOV BYTE PTR MENU+(22*6)+14,'N' ;Else mark rename function
- MOV BYTE PTR MENU+(22*6)+15,'/' ; Not/Available.
- MOV BYTE PTR MENU+(22*6)+16,'A'
- RENAME_OK: MOV AH,49H ;Return our memory segment.
- INT 21H
- MOV BX,2000H ;Request 128K.
- MOV AH,4AH
- INT 21H
- MOV DX,OFFSET NOT_ENOUGH ;If not available, exit
- JC QUIT ; with message.
-
- MOV AH,19H ;Get default drive and save.
- INT 21H
- MOV DEFAULT_DRIVE,AL
-
- ;-----------------------------------------------------;
- ; Check for drive request. Retrieve Disk Block info. ;
- ;-----------------------------------------------------;
-
- MOV AL,DS:[5CH] ;Get drive request.
- MOV BL,AL ;Save it.
- DEC AL ;Adjust.
- OR BL,BL ;If it was zero, no request.
- JNZ STORE_DRIVE
-
- MOV AH,19H ;Then get default drive.
- INT 21H
- STORE_DRIVE: MOV DRIVE,AL ;Store it.
- MOV DL,AL
- MOV AH,0EH ;Change drive to requested.
- INT 21H
-
- MOV DL,DRIVE ;Retrieve drive.
- INC DL ;Adjust.
- MOV AH,32H ;Retrieve Disk Block.
- INT 21H
- OR AL,AL ;Does disk request exist?
- JZ EXISTS
- JMP DISK_EXIT ;If no, exit with message.
- EXISTS: MOV SI,BX ;Store Disk Block.
- MOV DI,OFFSET DISK_BLOCK
- MOV CX,18
- REP MOVSB
- PUSH CS ;Restore data segment.
- POP DS
-
- CMP DRIVE,1 ;Is drive request A: or B:?
- JA CK_FREE
- JMP READ ;If yes, automatic read.
-
- ;---------------------------------------------------;
- ; Check to see if our database has been installed. ;
- ;---------------------------------------------------;
-
- CK_FREE: MOV AL,60H - 1 ;Available vectors are 60H - 67H.
- FREE_USER_INT: INC AL
- MOV AH,35H ;Get vector address.
- INT 21H
- CMP BX,0 ;Is offset being used?
- JNZ CK_SIGNATURE ;If yes, see if it's us.
- MOV DX,ES
- CMP DX,0 ;Is segment being used?
- JNZ CK_SIGNATURE ;If yes, see if it's us.
- MOV DATA_INT,AL ;If available, save INT number.
- JMP SHORT NEXT_USER ;Check all 7.
-
- CK_SIGNATURE: MOV DI,BX ;See if INT has our signature.
- MOV SI,OFFSET INSTALL_MSG
- MOV CX,30/2
- REPZ CMPSW
- JZ CK_SUBST ;If yes, already installed.
-
- NEXT_USER: CMP AL,67H ;Have we checked all 7?
- JNZ FREE_USER_INT ;If no, next one.
- CMP DATA_INT,0 ;Did we find one that was free?
- JNZ CK_SWITCH
- MOV DX,OFFSET NO_FREE ;If no, exit with message.
- JMP ERROR_EXIT
-
- CK_SWITCH: MOV SI,80H ;See if request to install.
- LODSB
- CMP AL,0 ;If no parameters, read data.
- JZ READ
- NEXT_SWITCH: LODSB
- CMP AL,13 ;End of parameters?
- JZ READ ;If yes, read data.
- CMP AL,'/' ;Switch character?
- JNZ NEXT_SWITCH
- LODSB
- AND AL,5FH
- CMP AL,'I' ;If yes, is it Install switch?
- JNZ READ
-
- INSTALL: MOV DX,103H ;If yes, point to signature.
- MOV AL,DATA_INT ;Retrieve free INT number.
- MOV AH,25H ;And install.
- INT 21H
- CALL FIRST_READ ;Read disk data.
- CALL CLS
- MOV DX,OFFSET INSTALL_MSG ;Display install message.
- MOV AH,9
- INT 21H
- CALL RESTORE_DRIVE ;Restore defaults.
- CALL CURSOR_ON
- MOV DX,OFFSET END_RESIDENT
- INT 27H ;Terminate and stay resident.
-
- ;-----------------------------------------------------;
- ; Check to see if drive request is a substitute. ;
- ; Also if different from current resident drive data. ;
- ;-----------------------------------------------------;
-
- CK_SUBST: MOV DATA_SEGMENT,ES ;Save the location of disk data.
- PUSH ES:CLUST_BYTES ;Retrieve from resident database
- POP CLUST_BYTES ; cluster size in bytes.
- MOV AL,DRIVE
- MOV DX,OFFSET UNKNOWN ;Is it a substituted drive?
- CMP AL,BYTE PTR DISK_BLOCK
- JZ CK_NEW_DRIVE ;If yes, exit with message.
- JMP DISK_EXIT
-
- CK_NEW_DRIVE: CMP AL,ES:DRIVE ;Is it a new drive request?
- JZ FORMAT ;If no, format resident data.
- MOV ES:DRIVE,AL ;Else, save new drive.
-
- ;--------------------------------------------------------------------;
- ; Read disk directory data, if necessary. Format it into a tree. ;
- ; Mark the current default directory. Clear the screen and display. ;
- ;--------------------------------------------------------------------;
-
- READ: CALL FIRST_READ
- FORMAT: CALL FORMAT_IT
- CALL GET_CURRENT
- CALL CLS
- CALL START_DISPLAY
-
- ;-----------------------------------------;
- ; We are now ready for business. We will ;
- ; loop here, waiting for user keystokes. ;
- ;-----------------------------------------;
-
- 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.
- CALL SEARCH ;Else, search request.
- JMP SHORT GET_KEY
- FUNCTION: MOV DI,OFFSET DISPATCH_KEY
- MOV AL,BH
- MOV CX,20 ;20 valid commands.
- REPNZ SCASB
- JNZ GET_KEY ;If no match, get another.
- MOV DI,OFFSET DISPATCH_TABLE+38
- SHL CX,1
- SUB DI,CX
- CALL DS:[DI] ;Else, do subroutine.
- JMP SHORT GET_KEY ;Update screen; get next command.
-
- ;-------------------------------------------------------------------;
- ; This is the exit routine. Restore defaults the way we found them. ;
- ;-------------------------------------------------------------------;
-
- ESC_EXIT: MOV DX,OFFSET CURRENT_DIR
- CALL CD
- EXIT: CALL RESTORE_DRIVE
- CALL CLS
- CALL CURSOR_ON
- XOR DX,DX ;Home cursor.
- CALL SET_CURSOR
- INT 20H ;And terminate.
-
- ;*************;
- ; SUBROUTINES ;
- ;*************;
-
- ;------------------------------------------------------------------------;
- ; This subroutine searches for a directory 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: CMP BL,'\' ;Searching for root?
- JNZ SEARCH_NAME
- CALL HOME_BAR ;If yes, home the bar.
- RET
-
- SEARCH_NAME: CALL GET_NAME ;Get current position.
- XOR DX,DX ;Zero out file counter.
- MOV DI,DIR_NAME ;Store current position in DI.
- MOV SI,OFFSET DIRECTORIES ;Point to top of listing.
- CMP BYTE PTR [DI],BL ;Are we currently at a match?
- JNZ INC_SEARCH ;If no, start from top.
- FIND_START: INC DX ;Increment count.
- ADD SI,DIR_RECORD ;Increment record.
- CMP SI,END_OFFSET ;End of tree?
- JAE SEARCH_BEEP ;If yes, no match.
- CMP SI,CUR_RECORD ;New record?
- JBE FIND_START ;If no, find it.
-
- NEXT_SEARCH: XOR BP,BP ;Zero in directory level pointer.
- FIND_DASH: INC BP
- CMP BYTE PTR [SI+BP-1],196 ;Is it the dash?
- JNZ FIND_DASH ;If no, find it.
-
- CMP BYTE PTR [SI+BP],BL ;Got a match?
- JZ FOUND_IT ;If yes, process.
- INC_SEARCH: ADD SI,DIR_RECORD ;Else, point to next record.
- INC DX
- CMP SI,END_OFFSET ;End of listing?
- JB NEXT_SEARCH ;If no, keep searching.
- SEARCH_BEEP: CALL BEEP ;No matches, so beep.
- RET
-
- FOUND_IT: MOV CX,DIR_COUNT ;Retrieve directory 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 MARK_IT
- NEXT_UP: CALL UP_ARROW ;Move up to matching filename.
- MARK_IT: DEC SEARCH_COUNT
- JNZ NEXT_UP
- MOV CL,INVERSE ;Turn bar back on and display.
- MOV BAR_ATTRIBUTE,CL
- XOR BP,BP
- CALL SCROLL_BAR
- RET
-
- ;-------------------------------------------------------------------------;
- ; This subroutine changes the directory to the one highlighted and exits. ;
- ;-------------------------------------------------------------------------;
-
- CHANGE_DIR: CALL GET_NAME
- CALL NEW_DIR
- JMP EXIT ;Exit.
-
- ;----------------------------------------------------;
- ; This subroutine renames the highlighted directory. ;
- ;----------------------------------------------------;
-
- RENAME: CMP DOS_VERSION,3 ;Can't rename directories before
- JB RENAME_ERROR ; DOS 3.x
- CALL GET_NAME
- CMP SI,OFFSET DIRECTORIES ;Can't rename the root directory.
- JZ RENAME_ERROR
- CALL NEW_DIR ;Change to the requested directory.
- JC RENAME_READ ;If nonexistant, reread data.
-
- MOV DX,162CH ;Row 22, column 44.
- MOV SI,OFFSET RENAME_MSG ;Display rename message.
- CALL QUERY ;Get new name from user.
- JC RENAME_END ;If carry, Esc was pressed.
-
- MOV DX,OFFSET DOT_DOT ;Change to parent directory.
- CALL CD
- MOV DX,DIR_NAME ;Point to old name.
- MOV DI,80H
- MOV AH,56H ;Rename.
- INT 21H
- JC RENAME_ERROR ;Beep if illegal.
- RENAME_READ: CALL REREAD ;Reread data.
- RENAME_END: CALL CLEAR_MSG
- RET
-
- RENAME_ERROR: CALL BEEP ;Error exit.
- CALL CLEAR_MSG
- RET
-
- ;-----------------------------------------------------------------------;
- ; This subroutine makes a subdirectory under the highlighted directory. ;
- ;-----------------------------------------------------------------------;
-
- MKDIR: CALL GET_NAME
- CALL NEW_DIR ;Change to the requested directory.
- JC MKDIR_READ ;If nonexistant, reread data.
- MOV DX,1629H ;Row 22; column 41.
- MOV SI,OFFSET PATH_LENGTH ;Display path message.
- CALL DISPLAY_TEXT
- CALL GET_COUNT ;And the path length.
- CALL GET_TEXT ;And end of message.
- CMP COUNT,63 ;Is it already 63 or more chars?
- JB MKDIR_QUERY
- CALL BEEP ;If yes, refuse to make directory.
- CALL DELAY
- JMP SHORT MKDIR_END
-
- MKDIR_QUERY: MOV DX,1729H ;Point to next row.
- CALL QUERY ;Get name from user.
- JC MKDIR_END ;If carry, Esc was pressed.
- MOV DX,80H
- MOV AH,39H ;Create the directory.
- INT 21H
- JC MKDIR_ERROR ;Beep if illegal.
- MKDIR_READ: CALL REREAD ;Reread data.
-
- MKDIR_END: CALL CLEAR_MSG
- RET
-
- MKDIR_ERROR: CALL BEEP ;Error exit.
- CALL CLEAR_MSG
- RET
-
- ;-------------------------------------------------------;
- ; This subroutine removes the highlighted subdirectory. ;
- ;-------------------------------------------------------;
-
- RMDIR: CALL GET_NAME
- MOV SI,DIR_NAME
- CMP SI,OFFSET DIRECTORIES ;Can't remove root directory.
- JZ RMDIR_ERROR
- CMP BYTE PTR [SI+DIR_RECORD+1],196 ;Can't remove directory
- JZ RMDIR_ERROR ; with a subdirectory.
- CALL NEW_DIR ;Change to requested directory.
- JC RMDIR_READ ;If nonexistant, reread data.
- CALL COUNT_THEM ;Count and display file count.
- CMP COUNT,0 ;If empty, remove directory.
- JZ REMOVE
-
- MOV DX,1729H ;Else, display file loss Warning.
- MOV SI,OFFSET RMDIR_MSG
- CALL DISPLAY_TEXT
- MOV DX,1829H
- CALL DISPLAY_TEXT
- CALL CURSOR_ON
- CALL READ_KEY ;Get response.
- CMP AH,15H ;If not "Y", exit.
- JNZ RMDIR_RETURN
- CALL WRITE_TEXT ;Else, display it.
- CALL READ_KEY ;Get next response.
- CMP AH,1CH ;If not carriage return, exit.
- JNZ RMDIR_RETURN
-
- CALL FIRST_MATCH ;Else, find all files and delete.
- CALL DELETE
- NEXT_DELETE: CALL NEXT_MATCHING
- JC REMOVE
- CALL DELETE
- JMP SHORT NEXT_DELETE
-
- REMOVE: MOV DX,OFFSET DOT_DOT ;Move to parent directory.
- CALL CD
- MOV DX,DIR_NAME
- MOV AH,3AH ;Remove requested directory.
- INT 21H
- JC RMDIR_ERROR
- RMDIR_READ: CALL REREAD ;Reread data.
- RMDIR_RETURN: CALL CLEAR_MSG
- RET
-
- RMDIR_ERROR: CALL BEEP ;Error exit.
- CALL CLEAR_MSG
- RET
-
- ;------------------------------------------------------------------;
- ; These two subroutines hide and unhide the highlighted directory. ;
- ;------------------------------------------------------------------;
-
- HIDE_UNHIDE: CALL GET_NAME
- CMP SI,OFFSET DIRECTORIES ;Can't hide root directory.
- JZ HIDE_ERROR
- MOV DX,1629H ;Row 22; column 41.
- MOV SI,OFFSET HIDE_MSG ;Display hide message.
- CALL DISPLAY_TEXT
- MOV SI,DIR_NAME
- CALL GET_TEXT
- MOV BP,2 ;Hidden attribute.
- CALL READ_KEY ;Get a keystroke.
- CMP AH,23H ;Is it "H"?
- JZ CHANGE_IT ;If yes, change attribute.
- XOR BP,BP ;Turn off hidden attribute.
- CMP AH,16H ;Is it "U"?
- JNZ HIDE_END ;If no, exit.
-
- CHANGE_IT: CALL NEW_DIR
- JC HIDE_READ ;If directory nonexistant, read.
- MOV DX,OFFSET DOT_DOT ;Change to parent directory.
- CALL CD
- MOV DX,DIR_NAME
- MOV CX,BP ;Retrieve requested attribute.
- CALL CHMOD ;And change it.
- HIDE_READ: CALL REREAD
- RET
-
- HIDE_ERROR: CALL BEEP
- HIDE_END: CALL CLEAR_MSG
- RET
-
- ;--------------------------------------------------------;
- ; This subroutine sets or resets the read-only attribute ;
- ; of all the files of the highlighted directory. ;
- ;--------------------------------------------------------;
-
- READ_ONLY: CALL GET_NAME
- CALL NEW_DIR
- JC SET_READ ;If nonexistant directory, reread.
- CALL COUNT_THEM ;Display file count.
- CMP COUNT,0 ;Is directory empty?
- JZ READ_END ;If yes, nothing to mark.
- MOV DX,1729H ;Row 23; column 41.
- MOV SI,OFFSET READ_ONLY_MSG ;Display read-only message.
- CALL DISPLAY_TEXT
- MOV STRIP_MASK,11111111B ;If read-only request, nothing
- MOV ADD_MASK, 00000001B ; to strip and add bit 1.
- CALL READ_KEY
- CMP AH,13H ;Is it "R"?
- JZ DO_READ ;If yes, turn on read-only bit.
- MOV STRIP_MASK,11111110B ;If NOT read-only request, strip
- MOV ADD_MASK,0 ; read-only bit and add nothing.
- CMP AH,16H ;Is it "U"?
- JNZ READ_RETURN ;If no, done here.
-
- DO_READ: CALL DO_ATTRIB ;Change the attribute.
- CALL CLEAR_LINE ;Clear keystroke prompt line.
- MOV DX,1729H ;Row 23; column 41.
- MOV SI,OFFSET HAVE_BEEN ;Display "have been" message.
- CALL DISPLAY_TEXT
- MOV SI,OFFSET READ_MSG ;Display rest of message.
- JMP SHORT SET_MSG
-
- READ_RETURN: CALL CLEAR_MSG
- RET
-
- READ_END: CALL DELAY
- RET
-
- SET_READ: CALL REREAD
- RET
-
- ;------------------------------------------------------;
- ; These two subroutines set and reset the archive bit. ;
- ;------------------------------------------------------;
-
- SET_RESET: CALL GET_NAME
- CALL NEW_DIR
- JC SET_READ ;If nonexistant directory, reread.
- CALL COUNT_THEM ;Display file count.
- CMP COUNT,0 ;Is directory empty?
- JZ SET_END ;If yes, nothing to mark.
- MOV DX,1729H ;Row 23; column 41.
- MOV SI,OFFSET ARCHIVE_MSG ;Display archive message.
- CALL DISPLAY_TEXT
- MOV STRIP_MASK,11111111B ;If set archive request, nothing
- MOV ADD_MASK, 00100000B ; to strip and add bit 1.
- CALL READ_KEY
- CMP AH,1FH ;Is it "S"?
- JZ DO_ARCHIVE ;If yes, turn on archive bit.
- MOV STRIP_MASK,11011111B ;If NOT archive request, strip
- MOV ADD_MASK,0 ; archive bit and add nothing.
- CMP AH,13H ;Is it "R"?
- JNZ READ_RETURN ;If no, done here.
-
- DO_ARCHIVE: CALL DO_ATTRIB ;Change the attribute.
- CALL CLEAR_LINE ;Clear keystroke prompt line.
- MOV DX,1729H ;Row 23; column 41.
- MOV SI,OFFSET HAVE_BEEN ;Display "have been" message.
- CALL DISPLAY_TEXT
-
- SET_MSG: CMP ADD_MASK,0 ;If add nothing, display strip
- JZ DISPLAY_MSG ; message.
- ADD SI,4 ;Else, display bit on message.
- DISPLAY_MSG: CALL GET_TEXT
- SET_END: CALL DELAY ;Wait for keystroke, then remove
- RET ; message.
-
- ;-----------------------------------------------;
- ; This subroutine displays the file count and ;
- ; displacement of the highlighted subdirectory. ;
- ;-----------------------------------------------;
-
- FILE_SUM: CALL GET_NAME
- CALL NEW_DIR ;Change to requested directory.
- JC REREAD ;If nonexistant, reread data.
- CALL COUNT_THEM ;Get file count and displacement.
- CALL DELAY ;Display count until keystroke.
- RET
-
- ;-------------------------------------------------------------------;
- ; This subroutine rereads the directory tree information from disk. ;
- ;-------------------------------------------------------------------;
-
- REREAD: MOV PAGE_END,21*160+323 ;Reset default values.
- MOV DIR_COUNT,1
- CALL CLEAR_MSG ;Clear the last message.
- MOV DX,162DH ;Row 22, column 45.
- MOV SI,OFFSET LOADING ;Display loading message.
- CALL DISPLAY_TEXT
- CALL READ_DATA ;Read the data.
- CALL FORMAT_IT ;Construct new tree.
- CALL START_DISPLAY ;Display menu.
- CALL CLEAR_MSG ;Clear sorting message.
- XOR BP,BP ;Update directory display.
- CALL SCROLL
- MOV SI,PAGE_END ;Move bar if below directory
- SUB SI,160 ; display.
- CMP SI,LINE
- JA REREAD_END
- CALL MOVE_BAR
- REREAD_END: RET
-
- ;----------------------------;
- ; This subroutine spawns DR. ;
- ;----------------------------;
-
- DR: CALL GET_NAME
- CALL NEW_DIR ;Change the default directory.
- MOV BX,1000H ;Shrink memory down to one segment.
- MOV AH,4AH
- INT 21H
-
- PUSH DS ;Save segment registers.
- PUSH ES
- CALL CLS ;Clear screen.
- CLI
- MOV STACK_SEG,SS ;Save stack segment and pointer.
- MOV STACK_PTR,SP
- STI
-
- MOV WORD PTR COM_LINE_PTR + 2,DS
- MOV AX,DS:[2CH] ;Retrieve environment segment.
- MOV ENVIRONMENT,AX ;And put in paramter block.
- MOV DS,AX ;And data segment.
-
- XOR AX,AX ;Zero out pointer.
- FIND_COMSPEC: MOV SI,AX ;Point to environment offset.
- INC AX ;Next offset.
- MOV DI,OFFSET COMSPEC ;Find "Comspec=".
- MOV CX,8
- REP CMPSB
- JNZ FIND_COMSPEC
- MOV DX,SI ;What follows is Command.com path.
- MOV BX,OFFSET ENVIRONMENT ;Point to parameter block.
- MOV AX,4B00H ;Execute.
- INT 21H
-
- CLI
- MOV SP,CS:STACK_PTR ;Restore stack segment and pointer.
- MOV SS,CS:STACK_SEG
- STI
- POP ES ;Restore segment registers.
- POP DS
-
- MOV DX,80H ;Restore Disk Transfer Address.
- MOV AH,1AH
- INT 21H
- MOV BX,2000H ;Restore dual memory segments.
- MOV AH,4AH
- INT 21H
- CALL CLS ;Clear screen.
- CALL START_DISPLAY ;Restore menu.
- RET
-
- ;--------------------------------------------------------------------------;
- ; 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,-21*40 ;Move up 21 lines.
- CALL SCROLL
- JMP SHORT BOTTOM_BAR
-
- PG_DN: MOV BP,21*40 ;Move down 21 lines.
- MOVE_PAGE: CALL SCROLL
- JMP SHORT TOP_BAR ;Move bar to top.
-
- HOME_BAR: MOV CUR_OFFSET,OFFSET DIRECTORIES ;Move listing to beginning.
- TOP_BAR: MOV SI,323 ;And move bar to top.
- CALL MOVE_BAR
- RET
-
- END_BAR: MOV BX,END_OFFSET ;Move listing to last page.
- SUB BX,21*DIR_RECORD
- CMP BX,OFFSET DIRECTORIES
- 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
-
- ;----------------------------------------------;
- ; These subroutines support the ten functions. ;
- ;----------------------------------------------;
-
- CHMOD: MOV AX,4301H
- INT 21H
- RET
-
- ;--------------------------------------;
-
- DELAY: MOV AH,1
- INT 16H ;Loop here until keystroke.
- JZ DELAY
- CALL CLEAR_MSG
- RET
-
- ;-------------------------------------;
-
- DELETE: MOV DX,80H+30 ;Point to filename.
- MOV AH,41H
- INT 21H
- RET
-
- ;--------------------------------------;
-
- DO_ATTRIB: CALL FIRST_MATCH ;Find first file.
- NEXT_SET: MOV CL,DS:[80H+21] ;Get old attribute.
- AND CL,STRIP_MASK ;Strip request.
- OR CL,ADD_MASK ;Add request.
- XOR CH,CH ;Zero in high half.
- MOV DX,80H+30 ;Point to filename.
- CALL CHMOD ;And change the attribute.
- CALL NEXT_MATCHING ;Do it to all files.
- JNC NEXT_SET
- RET
-
- ;--------------------------------------;
-
- FIRST_MATCH: MOV DX,OFFSET STAR_DOT_STAR
- MOV CX,7
- MOV AH,4EH
- INT 21H
- RET
-
- NEXT_MATCHING: MOV AH,4FH
- INT 21H
- RET
-
- ;------------------------------------------------------;
- ; This subroutine gets a directory name from the user. ;
- ;------------------------------------------------------;
-
- QUERY: CALL DISPLAY_TEXT ;Display caller's message.
- MOV SI,DIR_NAME ;Add directory name.
- CALL GET_TEXT
- INC DH ;Next row.
- CALL SET_CURSOR ;Move cursor.
- CALL CURSOR_ON ;Turn it on.
- MOV DI,80H ;Write nulls over old entry.
- XOR AX,AX
- MOV CX,18
- REP STOSW
- MOV DI,80H ;Initiate pointer for entry.
-
- GET_QUERY: CALL READ_KEY ;Get a character.
- CMP AL,27 ;Is it Esc?
- JZ QUERY_DONT ;Is yes, exit subroutine.
- CMP AL,':' ;Ignore ":\?*".
- JZ GET_QUERY
- CMP AL,'\'
- JZ GET_QUERY
- CMP AL,'?'
- JZ GET_QUERY
- CMP AL,'*'
- JZ GET_QUERY
- CMP AL,13 ;Is it carriage return?
- JZ QUERY_DO ;If yes, return, do request.
- CMP AL,8 ;Is it backspace?
- JNZ NOT_BS ;If no, skip.
- CMP DI,80H ;At beginning of field?
- JZ GET_QUERY ;If yes, skip.
- DEC DI ;Else, decrement pointer.
- MOV SI,OFFSET BS ;Erase last character.
- CALL GET_TEXT
- JMP SHORT GET_QUERY
- NOT_BS: CMP AL,32 ;Is it above space?
- JBE GET_QUERY ;If no, ignore.
- CMP DI,8CH ;End of entry field?
- JZ GET_QUERY ;If yes, ignore.
- STOSB ;Else, store byte.
- CALL WRITE_TEXT ;And write it to screen.
- JMP SHORT GET_QUERY ;Get next keystroke.
-
- QUERY_DO: MOV BYTE PTR DS:[DI],0 ;Convert to ASCIIZ.
- CLC
- RET
-
- QUERY_DONT: STC ;Indicate Esc was pressed.
- RET
-
- ;--------------------------------------------;
- ; This subroutine gets a file count and ;
- ; displacement of the highlighted directory. ;
- ;--------------------------------------------;
-
- COUNT_THEM: MOV COUNT,0 ;Zero out file counter.
- MOV CLUST_COUNT,0 ;And cluster counter.
- CALL FIRST_MATCH ;Get first file.
- JC DISPLAY_COUNT
-
- FIND_NEXT: INC COUNT ;Increment file count.
- MOV AX,DS:[80H+26] ;Retrieve low word
- MOV DX,DS:[80H+28] ; and high word of file size.
- DIV CLUST_BYTES ;Divide to get cluster count.
- OR DX,DX ;If remainder, increment count.
- JZ NO_REMAINDER
- INC CLUST_COUNT
- NO_REMAINDER: ADD CLUST_COUNT,AX ;Add cluster count.
- CALL NEXT_MATCHING ;Find rest of files.
- JNC FIND_NEXT
-
- DISPLAY_COUNT: MOV DX,1629H ;Row 22; column 41.
- CALL SET_CURSOR
- CALL GET_COUNT ;Display count.
- MOV SI,OFFSET FILE_COUNT ;And message.
- CALL GET_TEXT
- MOV SI,DIR_NAME ;Display parent directory.
- CALL GET_TEXT
- MOV SI,OFFSET USING ;Display rest of message.
- CALL GET_TEXT
- MOV AX,CLUST_COUNT ;Retrieve cluster count.
- XOR DX,DX ;Zero in high half.
- MOV BX,CLUST_BYTES
- MUL BX ;Multiply to get total bytes.
- MOV BX,1024
- DIV BX ;Divide by one K bytes.
- MOV COUNT,AX
- CALL GET_COUNT ;Convert count to ASCII.
- MOV AL,'K' ;Tack on "K".
- CALL WRITE_TEXT
- RET
-
- ;------------------------------------------------------;
- ; This subroutine displays the loading message and ;
- ; reads the disk on reads requested from command line. ;
- ;------------------------------------------------------;
-
- FIRST_READ: CALL CLS
- MOV DX,0C18H
- MOV SI,OFFSET LOADING
- CALL DISPLAY_TEXT
-
- ;-------------------------------------------------------------------;
- ; This subroutine reads the root directory and FAT from disk. ;
- ; Then finds subdirectories stacking them in the database one level ;
- ; at a time. Finally, the database is alphabetized by level. ;
- ;-------------------------------------------------------------------;
-
- READ_DATA: MOV AX,DISK_BLOCK[2] ;Retrieve bytes per sector.
- MOV BL,BYTE PTR DISK_BLOCK[4] ;And sectors per cluster -1.
- INC BL ;Adjust.
- XOR BH,BH ;Zero high byte.
- MOV CLUST_SECTORS,BX ;And save.
- MUL BX ;Get total bytes per cluster.
- MOV CLUST_BYTES,AX ;And save.
- MOV CX,32 ;Divide by bytes per directory.
- DIV CX
- MOV CLUST_RECORDS,AX ;And save.
-
- GET_ROOT: MOV AX,DISK_BLOCK[9] ;Retrieve number of root entries.
- MOV CX,32 ;Times 32 byte record length.
- MUL CX
- JNC NO_ERROR ;Problem if carry.
- DISK_EXIT: MOV DX,OFFSET UNKNOWN ;Display message and exit.
- ERROR_EXIT: CALL RESTORE_DRIVE
- MSG_EXIT: MOV AH,9
- INT 21H
- CALL CURSOR_ON
- INT 20H
-
- NO_ERROR: MOV BX,DISK_BLOCK[2] ;Divide by bytes per sector.
- DIV BX
- MOV ROOT_SECTORS,AX ;That's root length in sectors.
- MOV CX,AX ;Root length.
- MOV DX,DISK_BLOCK[16] ;Directory starting sector.
- MOV BX,OFFSET ROOT_DIRECTORY ;Read the root directory.
- CALL READ_DISK
-
- MOV AX,DATA_SEGMENT ;Get data storage segment.
- MOV ES,AX
- XOR BP,BP ;Tree level counter.
- XOR BX,BX ;Entry number counter.
- MOV SI,OFFSET ROOT_DIRECTORY ;Point to root directory.
- MOV DI,OFFSET DATA_BUFFER ;Point to database storage.
- MOV BYTE PTR ES:[DI],0FFH ;Initialize with end signature.
- MOV ES:LEVEL_ADDRESS,DI ;Store starting level address.
- MOV CX,DISK_BLOCK[9] ;Retrieve no. root directories.
- CALL STORE_RECORD ;Store them in database.
- CMP BX,0 ;BX returns with no. entries.
- JZ DATA_END ;If none, done here.
-
- GET_FAT: PUSH BX ;Save entry count.
- MOV AL,BYTE PTR DISK_BLOCK[15] ;Retrieve sectors for FAT.
- XOR AH,AH ;Zero in high byte.
- MOV CX,AX ;Save.
- MOV BX,DISK_BLOCK[2] ;Retrieve byte per sector.
- MUL BX ;Multiply to get total bytes.
- JC DISK_EXIT ;Problem if carry.
- CMP AX,65535-8192 ;Too big if over 56K.
- JA DISK_EXIT ;Display message and exit.
- MOV DX,DISK_BLOCK[6] ;Retrieve reserved sectors.
- MOV BX,OFFSET FAT ;Read the FAT.
- CALL READ_DISK
- JC ERROR_EXIT ;Exit if problem.
-
- POP BX ;Retrieve directory count.
- MOV AX,DATA_SEGMENT ;Point to database segment.
- MOV ES,AX
- MOV SI,OFFSET DATA_BUFFER ;And point to database offset.
- UP_LEVEL: INC BP ;Bump point to next level.
- INC BP
- MOV ES:[OFFSET LEVEL_ADDRESS+BP],DI ;Save level address.
- MOV CX,BX ;Retrieve record count.
- XOR BX,BX ;Zero out entry counter.
- NEXT_SECTOR: MOV DX,ES:[SI+16] ;Retrieve starting cluster.
-
- NEXT_CLUSTER: MOV LAST_CLUSTER,DX ;And save.
- PUSH CX ;Save some registers.
- PUSH BX
- CALL READ_CLUSTER ;Retrieve directory sector.
- POP BX
- MOV DX,ES:[SI+1] ;Retrieve parent entry number.
- PUSH SI
- MOV SI,OFFSET WORKSPACE ;Point to new directory.
- MOV CX,CLUST_RECORDS ;Retrieve records per cluster.
- CALL STORE_RECORD ;Store subdirectories in database.
- POP SI
- POP CX
- JC END_LEVEL ;If carry, last entry found.
- CALL CK_FAT ;Else, get next cluster.
- JNC NEXT_CLUSTER ;If carry, last cluster found.
-
- END_LEVEL: ADD SI,DATA_RECORD ;Else, point to next root entry.
- LOOP NEXT_SECTOR ;Find next subdirectory.
- CMP SI,DI ;Did we find any at this level?
- JNZ UP_LEVEL ;If yes, continue.
- MOV AX,0FFFFH ;Else, done; mark with signature.
- STOSB
- MOV ES:[OFFSET LEVEL_ADDRESS+BP+2],AX ;Mark level address.
- CALL SORT ;Alphabetize by level.
- DATA_END: PUSH CS ;Restore segment registers.
- PUSH CS
- POP DS
- POP ES
- RET
-
- ;-------------------------------------------------;
- ; This subroutine does the direct sector reading. ;
- ;-------------------------------------------------;
-
- READ_DISK: PUSH BP ;Call destroys all registers
- PUSH SI ; except segment registers
- PUSH DI ; so we have to preserve.
- PUSH DS
-
- MOV AL,DRIVE ;Retrieve drive.
- MOV SI,DS ;Point to second segment.
- ADD SI,1000H
- MOV DS,SI
- INT 25H ;Read the sectors.
- POP AX ;Get rid off flags left on stack.
-
- POP DS ;Restore registers.
- POP DI
- POP SI
- POP BP
- RET
-
- ;----------------------------------------;
- ; This subroutine will read CX clusters. ;
- ;----------------------------------------;
-
- READ_CLUSTER: MOV AX,LAST_CLUSTER ;Retrieve cluster number.
- MOV CX,CLUST_SECTORS ;Retrieve sectors per cluster.
- MUL CX ;Multiply to get sector start.
- MOV DX,AX
- ADD DX,DISK_BLOCK[11] ;Add start of first data cluster.
- SUB DX,CX ;Subtract to reflect cluster
- SUB DX,CX ; 2 as first logical data sector.
- MOV BX,OFFSET WORKSPACE ;Point to workspace.
- CALL READ_DISK ;And get data.
- RET
-
- ;------------------------------------------------------------------;
- ; This subroutine stores the level number, entry number, parent ;
- ; entry number, the directory name and attribute byte in database. ;
- ;------------------------------------------------------------------;
-
- STORE_RECORD: PUSH DS ;Point to second segment.
- MOV AX,CS
- ADD AX,1000H
- MOV DS,AX
-
- NEXT_RECORD: CMP BYTE PTR [SI],0 ;No more entries?
- JZ STORE_RETURN ;If yes, done here.
- TEST BYTE PTR [SI+11],10H ;Is it a directory?
- JZ LOOP_STORE ;If no, next entry.
- CMP BYTE PTR [SI],0E5H ;Is it a removed directory?
- JZ LOOP_STORE ;If yes, skip.
- CMP BYTE PTR [SI],'.' ;Is it a dot or dot-dot entry?
- JZ LOOP_STORE ;If yes, skip.
-
- PUSH SI
- MOV AX,BP ;Store level number.
- STOSB
- MOV AX,BX ;Store entry number.
- STOSW
- MOV AX,DX ;Store parent entry number.
- STOSW
- PUSH CX
- MOV CX,11 ;Store 11 bytes of name.
- REP MOVSB
- POP CX
- ADD SI,15 ;Store starting cluster.
- MOVSW
- INC BX ;Increment entry count.
- POP SI
- XOR AX,AX ;Assume not a hidden directory.
- TEST BYTE PTR [SI+11],2 ;Is it hidden?
- JZ STORE_ATTRIB ;If no, store null.
- MOV AX,'H' ;Else, store "H".
- STORE_ATTRIB: STOSW
-
- LOOP_STORE: ADD SI,32 ;Point to next entry.
- LOOP NEXT_RECORD
- POP DS ;Restore segment.
- CLC ;Indicate full sector.
- RET
-
- STORE_RETURN: POP DS ;Indicate not full sector.
- STC
- RET
-
- ;-------------------------------------------------------------------;
- ; This subroutine finds the next cluster in the chain from the FAT. ;
- ;-------------------------------------------------------------------;
-
- CK_FAT: PUSH ES ;Save some registers.
- PUSH BX
- PUSH CX
- MOV AX,CS ;Point to second segment.
- ADD AX,1000H
- MOV ES,AX
-
- MOV AX,LAST_CLUSTER ;Retrieve last cluster.
- PUSH AX ;Save.
- XOR DX,DX ;Zero in high half.
- CMP DISK_BLOCK[13],0FF6H ;Number of clusters above 4085?
- JA SIXTEEN_BIT ;If yes, 16 bit FAT.
- TWELVE_BIT: MOV BX,15 ;Else, 12 bit FAT.
- MUL BX ;Multiply by 1.5 (or 15/10).
- MOV BX,10
- DIV BX
- MOV BX,AX
- MOV DX,ES:FAT[BX] ;Retrieve cluster pointer.
- POP AX ;Retrieve last cluster.
- TEST AX,1 ;Was last cluster even number?
- JZ LOW_ORDER ;If yes, use low order 12 bits.
- MOV CL,4 ;Else, high order 12 bits.
- SHR DX,CL ;Shift right 4 bits.
- JMP SHORT CK_12BIT
- LOW_ORDER: AND DX,0000111111111111B ;Mask off top 4 bits.
- CK_12BIT: CMP DX,0FF8H ;Is it end of chain?
- JAE CLUSTER_END ;If yes, indicate so.
- JMP SHORT RETURN_CLUST ;Else, return with cluster in DX.
-
- SIXTEEN_BIT: POP BX ;Retrieve last cluster.
- SHL BX,1 ;Multiply by 2.
- MOV DX,ES:FAT[BX] ;Retrieve next cluster number.
- CMP DX,0FFF8H ;Is it end of chain?
- JAE CLUSTER_END ;If yes, indicate so.
-
- RETURN_CLUST: POP CX ;Restore registers.
- POP BX
- POP ES
- CLC ;Indicate not end of chain.
- RET
-
- CLUSTER_END: POP CX
- POP BX
- POP ES
- STC ;Indicate end of cluster chain.
- RET
-
- ;--------------------------------------------------------;
- ; This subroutine alphabetizes the directories by level. ;
- ;--------------------------------------------------------;
-
- SORT: PUSH DS
- MOV AX,DATA_SEGMENT ;Point to database segment.
- MOV ES,AX
- MOV DS,AX
- XOR BP,BP ;Zero in level pointer.
- LEVEL_SORT: MOV DX,ES:[OFFSET LEVEL_ADDRESS+BP+2] ;Retreive level offset.
- CMP DX,0FFFFH ;End signature?
- JZ SORT_RETURN ;If yes, done here.
- SUB DX,DATA_RECORD ;Point to end of lower level.
- PUSH BP ;Save level pointer.
-
- NEXT_PASS: POP BP
- PUSH BP
- MOV BX,ES:[OFFSET LEVEL_ADDRESS+BP] ;Point to start of level.
- XOR BP,BP ;Zero in exchange flag.
- CMP BX,DX ;End of level?
- JZ SORT_SET ;If yes, next level.
-
- NEXT_SORT: MOV SI,BX ;Source and destination.
- ADD SI,5 ;Point to name
- MOV DI,BX ; in each record.
- ADD DI,DATA_RECORD+5
- MOV CX,11
- REPZ CMPSB ;Compare names.
- JBE END_SORT ;If already in order, skip.
-
- MOV SI,BX ;Else, recover pointers.
- MOV DI,BX
- ADD DI,DATA_RECORD
- MOV CX,DATA_RECORD/2 ;Exchange the records.
- NEXT_SWAP: MOV AX,[DI]
- MOVSW
- MOV [SI-2],AX
- LOOP NEXT_SWAP
- MOV BP,1 ;Flag that exchange was made.
-
- END_SORT: ADD BX,DATA_RECORD ;Point to next record.
- CMP BX,DX ;End of top?
- JB NEXT_SORT ;If no, bubble sort next.
- SUB DX,DATA_RECORD ;Else, move top down one record.
- CMP BP,0 ;Was there exchange made?
- JNZ NEXT_PASS
-
- SORT_SET: POP BP
- INC BP ;Next level.
- INC BP
- JMP SHORT LEVEL_SORT ;Sort it.
-
- SORT_RETURN: POP DS ;Restore data segment.
- RET
-
- ;-------------------------------------------------------------;
- ; This subroutine formats the database into a directory tree. ;
- ;-------------------------------------------------------------;
-
- FORMAT_IT: PUSH DATA_SEGMENT ;Point to database segment.
- POP DS
- MOV AX,CS ;Point to second segment.
- ADD AX,1000H
- MOV ES,AX
- MOV SI,OFFSET LEVEL_ADDRESS ;Move resident database
- MOV DI,SI ; into our second segment.
- MOV CX,100+(DATA_RECORD*500/2)
- REP MOVSW
-
- PUSH CS ;Restore segment registers.
- PUSH CS
- POP DS
- POP ES
- CALL STORE_ROOT ;Initialize with "\ (ROOT)".
-
- XOR BP,BP ;Zero in level pointer.
- MOV SI,OFFSET DATA_BUFFER ;Point to database.
- MOV DI,OFFSET DIRECTORIES+DIR_RECORD+1 ;Point to storage.
- MOV LAST_ENTRY,DI ;Save current entry.
- MOV AX,CS ;Point to second segment.
- ADD AX,1000H
- MOV DS,AX
- CMP BYTE PTR [SI],0FFH ;No subs signature?
- JZ SKIP_FORMAT ;If yes, skip format.
-
- NEXT_FORMAT: CALL STORE_NAME ;Format the directory name.
- ADD SI,DATA_RECORD ;Point to next record.
- CMP BYTE PTR [SI],0 ;End of root directory?
- JZ NEXT_FORMAT ;If no, get next entry.
- SKIP_FORMAT: PUSH CS ;Else, done.
- POP DS ;Restore data segment.
- DEC DI ;Adjust end pointer.
- MOV END_OFFSET,DI ;And save.
- MOV BX,DIR_COUNT ;Retrieve directory count.
- CMP BX,21 ;Enough to fill one page?
- JAE FORMAT_END ;If yes, use default setting.
- MOV AX,160 ;Calculate last record.
- MUL BL
- ADD AX,323 ;Add bar offset.
- MOV PAGE_END,AX ;And save.
- FORMAT_END: RET
-
- ;------------------------------------------------------;
- ; This subroutine initializes the directory tree image ;
- ; with nulls and makes the first record "\ (ROOT)". ;
- ;------------------------------------------------------;
-
- STORE_ROOT: MOV AX,0
- MOV DI,OFFSET DIRECTORIES
- MOV CX,30000 / 2
- REP STOSW
-
- MOV DI,OFFSET DIRECTORIES
- MOV SI,OFFSET ROOT
- MOV CX,8
- REP MOVSB
- RET
-
- ;-----------------------------------------------------------;
- ; This subroutine recursively builds the subdirectory tree. ;
- ;-----------------------------------------------------------;
-
- STORE_NAME: PUSH SI ;Save a couple registers.
- PUSH BP
-
- PUSH DI ;Save pointers.
- PUSH SI
- PUSH SI
- MOV SI,CS:LAST_ENTRY ;Retrieve last entry.
- MOV DX,DI ;Retrieve current position.
- CMP SI,DX ;Have stored any subdirectories?
- JZ STORE_DIR ;If no, skip tree structuring.
- MOV BYTE PTR CS:[SI+BP],195 ;Store connecting T character.
- PLACE_BAR: ADD SI,DIR_RECORD ;Move to next record.
- CMP SI,DX ;Are we at the current record?
- JZ STORE_DIR ;If yes, done here.
- MOV BYTE PTR CS:[SI+BP],179 ;Else, store vertical line char.
- JMP SHORT PLACE_BAR ;Repeat until up to date.
-
- STORE_DIR: MOV CS:LAST_ENTRY,SI ;Store current position.
- POP SI ;Restore current record pointer.
- INC CS:DIR_COUNT ;Increment directory counter.
- ADD DI,BP ;Add level pointer.
- MOV AL,192 ;Store L line character.
- STOSB
- MOV AL,196 ;Store horizontal line character.
- STOSB
- ADD SI,5 ;Point to directory name.
- MOV CX,8
- CALL STORE_BYTES ;And store in tree.
- CMP BYTE PTR [SI],32
- JZ END_NAME
- MOV AL,'.' ;If exists, append extension.
- STOSB
- MOV CX,3
- CALL STORE_BYTES
- END_NAME: POP SI ;Restore current record pointer.
- INC DI ;Bump pointer for space.
- MOV AL,[SI+18] ;Retrieve "hidden" field.
- STOSB ;And store it.
- NEXT_DEST: POP DI ;Restore destination pointer.
- ADD DI,DIR_RECORD ;Point to next tree record.
-
- PUSH CS:LAST_ENTRY ;Save current position pointer.
- MOV CS:LAST_ENTRY,DI ;Save our current position.
- INC BP ;Bump pointer to next level.
- INC BP
- MOV BX,DS:[OFFSET LEVEL_ADDRESS+BP] ;Get level offset.
-
- NEXT_SUB: MOV AL,DS:[BX] ;Retrieve level pointer.
- XOR AH,AH
- CMP AX,BP ;Is it our level?
- JA STORE_END ;If next level, done here.
- MOV AX,DS:[BX+3] ;Retrieve parent entry number.
- CMP AX,DS:[SI+1] ;Is it our entry number?
- JNZ SKIP_SUB ;If no, check next record.
-
- GET_SUB: PUSH BX ;Else, save pointers.
- PUSH SI
- MOV SI,BX ;Point to our offset.
- CALL STORE_NAME ;Store subdirectory.
- POP SI ;Restore pointers.
- POP BX
-
- SKIP_SUB: ADD BX,DATA_RECORD ;Next record.
- JMP SHORT NEXT_SUB
-
- STORE_END: POP CS:LAST_ENTRY ;Restore last entry pointer.
- POP BP
- POP SI
- RET
-
- ;--------------------------------------;
-
- STORE_BYTES: LODSB ;Store all non space name
- CMP AL,32 ; characters.
- JZ SKIP_STORE
- STOSB
- SKIP_STORE: LOOP STORE_BYTES
- RET
-
- ;-----------------------------------------------------------------;
- ; This subdirectory works its way back to the root directory from ;
- ; the currently highlighted directory and then retraces back up ;
- ; the tree changing the default directory one level at a time. ;
- ;-----------------------------------------------------------------;
-
- NEW_DIR: MOV COUNT,0 ;Zero out path counter.
- MOV DX,OFFSET ROOT_DIR ;Change to root directory.
- CALL CD
- XOR CX,CX ;Zero in level counter.
- MOV DI,CUR_RECORD ;Point to highlighted record.
- CMP DI,OFFSET DIRECTORIES ;Is it the root?
- JZ NEW_DIR_END ;If yes, done here.
- MOV BX,DIR_NAME ;Point to directory name.
- DEC BX ;Point to horizontal character.
-
- NEXT_SUBDIR: MOV SI,BX
- FIND_DIR: LODSB ;Get a byte.
- CMP AL,196 ;Is it horizonatal character?
- JNZ FIND_DIR ;If no, find it.
- PUSH SI ;Save directory.
- INC CX ;Also keep track of level.
- NEXT_PATH: INC COUNT ;Increment path length.
- LODSB
- CMP AL,0 ;Are we at end of directory name?
- JNZ NEXT_PATH ;If no, find it.
- CMP BYTE PTR [DI+2],196 ;Is there a level under us?
- JZ CHANGE_THEM ;If no, done here.
- DEC BX ;Else, decrement level pointer.
- DEC BX
- NEXT_LEVEL: SUB DI,DIR_RECORD ;Look for next lower level.
- SUB BX,DIR_RECORD
- CMP BYTE PTR [BX],196 ;Have we found parent record?
- JNZ NEXT_LEVEL ;If no, find it.
- JMP SHORT NEXT_SUBDIR ;And find name and length.
-
- CHANGE_THEM: POP DX ;Retrieve directory name pointer.
- CALL CD ;Change directories.
- JC RESTORE_STACK ;If nonexistant, restore stack
- LOOP CHANGE_THEM ;Else, continue up the tree.
- NEW_DIR_END: RET
-
- NEXT_STACK: POP DX ;If error, restore stack
- RESTORE_STACK: LOOP NEXT_STACK ; before returning.
- RET
-
- ;--------------------------------------;
-
- CD: MOV AH,3BH
- INT 21H
- RET
-
- ;--------------------------------------------------;
- ; This subroutine finds the highlighted directory. ;
- ;--------------------------------------------------;
-
- GET_NAME: MOV SI,CUR_OFFSET ;Get top of page.
- MOV AX,LINE ;Get location of bar.
- SUB AX,323 ;Adjust.
- MOV CL,160 ;80 characters + 80 attributes.
- DIV CL ;Divide to get line number.
- MOV CL,DIR_RECORD ;Times directory record length.
- MUL CL
- ADD SI,AX ;Add to current offset.
- MOV CUR_RECORD,SI ;And save pointer.
- CMP CUR_RECORD,OFFSET DIRECTORIES ;Is it top line?
- JZ NAME_RETURN ;If yes, done here.
- FIND_TOP: LODSB
- CMP AL,196 ;Is it the horizontal line char?
- JNZ FIND_TOP ;If no, find it.
- NAME_RETURN: MOV DIR_NAME,SI ;And store name pointer.
- RET
-
- ;----------------------------------------------------------;
- ; This subdirectory searches through the graphic tree for ;
- ; the name of the DOS default directory and highlights it. ;
- ;----------------------------------------------------------;
-
- GET_CURRENT: MOV SI,OFFSET CURRENT_DIR ;Point to default directory.
- MOV BYTE PTR [SI],'\' ;DOS fails to include starting "\".
- INC SI ;Point to first level.
- MOV DL,DRIVE ;Retrieve drive.
- INC DL ;Convert to DOS format.
- MOV AH,47H ;Retrieve current directory.
- INT 21H
- CALL CAPITALIZE ;Capitalize it.
-
- MOV BX,OFFSET CURRENT_DIR+1 ;Point to default directory.
- CMP BYTE PTR [BX],0 ;Are we at end?
- JZ CURRENT_END ;If yes, done here.
- MOV BP,OFFSET DIRECTORIES+DIR_RECORD+3 ;Store pointer.
- XOR DX,DX ;Zero entry counter.
- MOV CX,500 ;Search a maximum of 500 records.
-
- NEXT_DEFAULT: INC DX ;Increment entry counter.
- MOV SI,BX ;Point to default directory.
- MOV DI,BP ;Point to directory tree.
- CMP BYTE PTR [DI-1],196 ;Is it horizontal bar?
- JNZ NO_MATCH ;If no, next record.
- NEXT_MATCH: CMP BYTE PTR [DI],0 ;Is it end of tree name?
- JNZ CK_DEFAULT ;If no, see if name matches.
- CMP BYTE PTR [SI],'\' ;Is it end of default level?
- JZ MATCH ;If yes, then we have a match.
- CMP BYTE PTR [SI],0 ;Zero also marks name end.
- JZ MATCH
- CK_DEFAULT: CMPSB ;Character in name match?
- JZ NEXT_MATCH ;If yes, check next byte.
- NO_MATCH: ADD BP,DIR_RECORD ;Else, next record.
- LOOP NEXT_DEFAULT ;Search up to 500 records.
- JMP SHORT CURRENT_END ;Give up if not found.
-
- MATCH: DEC CX ;Decrement search counter.
- JZ CURRENT_END ;Exit, if not found.
- INC SI ;Point to name.
- MOV BX,SI ;Store current level.
- ADD BP,DIR_RECORD+2 ;Point to next record and level.
- CMP BYTE PTR [SI-1],0 ;End of default?
- JNZ NEXT_DEFAULT ;If no, continue.
-
- FIND_DEFAULT: MOV CX,DIR_COUNT ;Retrieve directory count.
- SUB CX,DX ;Subtract default entry counter.
- MOV SEARCH_COUNT,CX ;Save.
- 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 directory.
- FIND_IT: DEC SEARCH_COUNT
- JNZ NEXT_FIND
- MOV CL,INVERSE ;Turn bar back on.
- MOV BAR_ATTRIBUTE,CL
- CURRENT_END: RET
-
- ;-----------------------------------------------------;
- ; This subroutine displays the menu, requested drive, ;
- ; and directory count. Also displays highlight bar. ;
- ;-----------------------------------------------------;
-
- START_DISPLAY: MOV SI,OFFSET MENU ;Point to menu position.
- MOV DI,(2*160)+98 ;And to screen position.
- MOV BH,19 ;Display 19 lines of menu.
- NEXT_FUNCTION: 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_FUNCTION
-
- MOV SI,OFFSET HEADING ;Display "Directories of drive".
- MOV DX,1
- CALL DISPLAY_TEXT
- MOV AL,DRIVE
- ADD AL,'A' ;Display drive.
- CALL WRITE_TEXT
- MOV AL,':' ;And colon.
- CALL WRITE_TEXT
- CALL COUNT_DIRS ;Display directory count.
- MOV SI,LINE
- CALL MOVE_BAR ;Highlight the current directory.
- RET
-
- ;----------------------------------------------------;
- ; This subroutine capitalizes the default directory. ;
- ;----------------------------------------------------;
-
- CAPITALIZE: CMP BYTE PTR [SI],'a'
- JB NEXT_CAPS
- CMP BYTE PTR [SI],'z'
- JA NEXT_CAPS
- AND BYTE PTR [SI],5FH
- NEXT_CAPS: INC SI
- CMP BYTE PTR [SI],0
- JNZ CAPITALIZE
- 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 DIRECTORIES ;If above start check upper limit.
- JAE UPPER_LIMIT
- LOWER_LIMIT: MOV CUR_OFFSET,OFFSET DIRECTORIES ;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 DIRECTORIES+21*DIR_RECORD ; directory listing.
- JA CK_UPPER
- MOV CUR_OFFSET,OFFSET DIRECTORIES
- JMP SHORT SCROLL_RETURN
-
- CK_UPPER: SUB BX,21*DIR_RECORD
- CMP SI,BX
- JBE END_SCROLL
- MOV SI,BX
-
- END_SCROLL: MOV CUR_OFFSET,SI ;Update current offset.
- MOV SI,LINE
- CALL MOVE_BAR
- 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,-DIR_RECORD ;Assume below beginning.
- CMP SI,323 ;Is it?
- JB SCROLL_PAGE ;If yes, scroll page instead.
- MOV BP,DIR_RECORD ;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 DI,BAR_START ;Remove old bar.
- MOV CX,BAR_LENGTH
- MOV BL,NORMAL
- NEXT_BAR: CALL WRITE_SCREEN
- LOOP NEXT_BAR
-
- MOV LINE,SI ;And move bar to new line.
- MOV BL,BAR_ATTRIBUTE
- CALL GET_NAME
- MOV SI,CUR_RECORD ;Retrieve current record.
- MOV DI,LINE ;Retrieve line.
- MOV BAR_LENGTH,0 ;Zero out bar length counter.
- START_BAR: LODSB
- CMP AL,'\' ;Is it the root?
- JZ SAVE_START ;If yes, done here.
- INC DI ;Increment bar pointer
- INC DI ; past character as well.
- CMP AL,196 ;Is it horizontal bar character?
- JNZ START_BAR ;If no, find it.
- INC SI ;Bump point to start of name.
-
- SAVE_START: MOV BAR_START,DI ;Save.
- DISPLAY_BAR: INC BAR_LENGTH ;Increment bar length counter.
- MOV CX,1
- CALL WRITE_SCREEN ;Write the attribute.
- LODSB
- CMP AL,0 ;Are we at end of name?
- JNZ DISPLAY_BAR ;Continue until done.
- RET
-
- ;-------------------------------------------------;
- ; This subroutine displays the directory listing. ;
- ;-------------------------------------------------;
-
- UPDATE_SCREEN: XOR BP,BP
- MOV SI,CUR_OFFSET ;Retrieve starting offset.
- MOV DI,2*160+2 ;Point to row two of screen.
- MOV BH,21 ;21 lines to write.
- NEXT_WRITE: MOV CX,40 ;40 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,80 ;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.
-
- WAIT: IN AL,DX ;Get status.
- TEST AL,1 ;Is it high?
- JZ WAIT ;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: CALL CURSOR_OFF
- MOV CX,1629H ;Row 22; column 41.
- MOV DX,184FH ;Row 24; column 79.
- JMP SHORT CLEAR_WINDOW
-
- CLEAR_LINE: MOV CX,1729H ;Row 23; column 41.
- MOV DX,174FH ;Row 23; 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 four subroutines move the cursor, get the current ;
- ; directory, beep the speaker or get a keystroke. ;
- ;---------------------------------------------------------;
-
- SET_CURSOR: PUSH SI
- XOR BH,BH ;Page zero.
- MOV AH,2 ;Set cursor.
- INT 10H
- POP SI
- 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
-
- ;-----------------------------------------------;
- ; 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 displays the count of files. ;
- ;----------------------------------------------;
-
- COUNT_DIRS: MOV DX,1802H ;Row 24; column 2.
- CALL SET_CURSOR
- MOV AX,DIR_COUNT
- CALL GET_DIR_COUNT
- MOV SI,OFFSET DIR_MSG ;Display directory count.
- CALL GET_TEXT
- RET
-
- ;------------------------------------------;
- ; This subroutine converts hex to decimal. ;
- ;------------------------------------------;
-
- GET_COUNT: MOV AX,COUNT
- GET_DIR_COUNT: MOV BX,10 ;Convert to decimal.
- XOR CX,CX ;Zero in counter.
- NEXT_COUNT: XOR DX,DX
- DIV BX
- ADD DL,'0' ;Convert to ASCII.
- PUSH DX ;Save results.
- INC CX ;Also increment count.
- CMP AX,0 ;Are we done?
- JNZ NEXT_COUNT
-
- NEXT_NUMBER: POP AX ;Retrieve numbers.
- CALL WRITE_TEXT ;And write them.
- LOOP NEXT_NUMBER
- RET
-
- ;---------------------------------------------;
- ; This subroutine restores the current drive. ;
- ;---------------------------------------------;
-
- RESTORE_DRIVE: PUSH DX
- MOV DL,DEFAULT_DRIVE
- MOV AH,0EH
- INT 21H
- POP DX
- RET
-
- ;------------------------------------;
-
- DISK_BLOCK LABEL WORD
- CURRENT_DIR EQU DISK_BLOCK+18
- LEVEL_ADDRESS EQU CURRENT_DIR+65
- DIRECTORIES EQU LEVEL_ADDRESS+100
- DATA_BUFFER EQU LEVEL_ADDRESS+100
- END_RESIDENT EQU DATA_BUFFER+(DATA_RECORD*500)
-
- CODE ENDS
- END START
-