home *** CD-ROM | disk | FTP | other *** search
- ;TASM source for S.COM v.1.5. Copyright (C) DA Nye, 1992, all rights reserved.
-
- ideal
- model tiny
-
- NFILES EQU 200 ;Max # files in display
-
- FILESPEC EQU 82h ;Address of filespec in command tail
- PATH EQU 81h ;Count of chars in path part of filespec here
- NORMAL_FILE EQU 11100001b ;Attribute for a normal file
- TAGGED EQU 80h ;Bit to set in attrib to indicate file tagged
- DTA_ATTRIB EQU DTA+21 ;Offsets of elements in DTA
- DTA_TIME EQU DTA+22
- DTA_DATE EQU DTA+24
- DTA_SIZE EQU DTA+26
- DTA_NAME EQU DTA+30
- FILE_TIME EQU bp ;Addrs of elements in 'fileRecords' after name
- FILE_DATE EQU bp+2
- FILE_SIZE EQU bp+4
- COPYVAL EQU 1 ;Keys for Copy/Move/Delete/Rename operations
- DELETEVAL EQU 2
- MOVEVAL EQU 3
- RENAMEVAL EQU 4
-
- codeseg
- BOF:
- org 100h
-
- Start:
- mov sp, OFFSET stackEnd ;Initialize stack
- sub ax, ax
- push ax
- mov [programSeg], cs ;Save current value of CS -> program segment
- mov ah, 0Fh ;Find display memory
- int 10h
- mov di, 0B000h ;If mode 7 (= MDA or Herc), video seg=B000h,
- cmp al, 7
- je @@L1
- mov di, 0B800h ;Otherwise video seg=B800h,
- @@L1:
- mov es, di ;Unless running under DesqView
- mov cx, 'DE'
- mov dx, 'SQ'
- mov ax, 2B01h
- int 21h
- cmp al, 0FFh
- je @@L2
- mov ah, 0FEh
- int 10h
- mov di, es
- @@L2:
- mov [displaySegment], di
- mov es, di ;Remember original screen color at lower right
- mov al, [es:3999]
- mov [original], al
- mov es, [2Ch] ;Find COMSPEC
- sub di, di
- @@L3:
- mov si, OFFSET comspec
- mov cx, 8
- repe cmpsb
- jne @@L3
- mov [comspecOff], di
- mov [comspecSeg], es
- mov es, [programSeg]
- NewSpec:
- mov si, FILESPEC ;Examine command line filespec
- mov di, si
- cmp [byte FILESPEC-2], 1 ;If none, use "*.*"
- jbe @@L3
- @@L1:
- lodsb
- cmp al, '*' ;Look for wildcard chars
- je GetPathLength
- cmp al, '?'
- je GetPathLength
- cmp al, 0Dh
- jne @@L1
- cmp [byte si-2], '\' ;If none, assume spec is a directory
- jne @@L2
- dec si ;If last char was not '\', add it
- jmp SHORT @@L3
- @@L2:
- mov [byte si-1], '\'
- @@L3:
- mov ax, si ;Compute length of path minus filename
- sub ax, di
- mov [PATH], al
- mov di, si
- NewDir:
- mov [keepSorted], 0 ;Directory is initially unsorted
- mov si, OFFSET starDotStar ;Append '*.*',0
- call CopyString
- jmp SHORT Restart
- NoRoomError:
- mov dx, OFFSET noRoomMsg ;Not enough room to run S
- Abort:
- call BlankScreen
- mov ah, 9
- int 21h
- mov ax, 4C00h ;Bye
- int 21h
-
- GetPathLength:
- mov al, [byte FILESPEC-2] ;Null-terminate other filespecs
- sub ah, ah
- mov si, ax
- add si, FILESPEC-1
- mov [si], ah
- mov cx, ax ;Count chars in path excluding file name:
- std ;Search backward for last '\' or ':'
- @@L1:
- lodsb
- cmp al, '\'
- je @@L2
- cmp al, ':'
- loopne @@L1
- @@L2:
- cld
- mov [PATH], cl
-
- Restart:
- mov ax, OFFSET files ;Cursor -> first file
- mov [cursor], ax
- mov [top], ax
- Restart0:
- mov bx, (EOF-BOF)/16+1 ;Resize memory to amount needed
- mov ah, 4Ah
- int 21h
- jc NoRoomError
- mov ah, 19h ;Get default drive for path/spec display
- int 21h
- add al, 'A'
- mov di, OFFSET pathNSpec ;Store letter, ':\'
- stosb
- mov ax, '\:'
- stosw
- mov si, di ;Get path and name of current directory
- sub dl, dl
- mov ah, 47h
- int 21h
- sub al, al ;Find end
- mov cx, -1
- repne scasb
- dec di
- mov ax, ' '+100h*' ' ;Add two spaces
- stosw
- mov si, FILESPEC ;Append filespec
- call CopyString
-
- ;Get all file names matching filespec and set up tables
- GetFileRecords:
- mov dx, OFFSET DTA ;Set up DTA
- mov ah, 1Ah
- int 21h
- sub ax, ax ;Initialize file size total
- mov [totalSize], ax
- mov [totalSize+2], ax
- mov dx, FILESPEC ;Get first file name
- mov cl, 37h
- mov ah, 4Eh
- int 21h
- jnc FileFound ;No files. Try a different filespec.
- mov si, OFFSET NoFilesMsg
- call Error
- jmp NewFilespec
- FileFound:
- mov di, OFFSET fileRecords ;DI -> storage for file names
- mov bx, OFFSET files ;BX -> array of files
- sub bx, 2
- StoreFileName:
- add bx, 2 ;For all files that will fit,
- cmp bx, (OFFSET files) + NFILES*2
- jb @@L1
- sub bx, 2
- mov [last], bx
- mov si, OFFSET tooManyMsg
- jmp DoError
- @@L1:
- mov [bx], di ;Store pointer to status/filename in files[]
- mov al, [DTA_ATTRIB] ;Store status byte
- and al, 3Fh ;Top bit is used to indicate file is marked
- stosb
- mov si, OFFSET DTA_NAME ;Copy file name from DTA to filename storage
- call CopyString
- inc di
- mov si, OFFSET DTA_TIME ;Copy time, date and size
- mov cx, 4
- rep movsw
- test [DTA_ATTRIB], 10h ;If not a subdirectory,
- jnz @@L2
- mov si, OFFSET DTA_SIZE ;Add size to total
- lodsw
- add [totalSize], ax
- lodsw
- adc [totalSize+2], ax
- @@L2:
- mov ah, 4Fh ;Next filename
- int 21h
- jnc StoreFileName
- mov [last], bx ;Save pointer to last file entry
- mov al, [keepSorted] ;If returning from EXEC, need to resort files?
- or al, al
- jz DisplayFiles
- jmp Sort0
-
- ;Main loop. Display files and wait for command.
- DisplayFiles:
- call BlankStatus ;Clear status line
- mov si, OFFSET helpF1 ;Display help key
- call DisplayString
- mov bx, [cursor]
- mov si, [bx]
- lodsb ;Get attributes of file at cursor
- mov [attrib], al ;Save attribute byte
- call DisplayString ;Display name of highlighted file
- mov bp, si ;Save pointer to time, date, size
- test [attrib], 10h ;If a directory,
- jz @@L7
- mov si, OFFSET dirMsg ; show '<DIR>' instead of file size
- add di, 2
- call DisplayString
- jmp SHORT @@L9
- @@L7:
- lea si, [FILE_SIZE] ;File size, right justified
- add di, 14
- call WriteLongDecimal
- @@L9:
- add di, 18 ;File date:
- push di
- sub dx, dx
- mov bx, [FILE_DATE] ;Year
- mov al, bh
- shr al, 1
- add al, 80
- sub ah, ah
- mov cl, 2
- call WriteDecimal
- mov al, '/'
- stosw
- mov ax, bx ;Day
- and ax, 1Fh
- mov cx, 2
- call WriteDecimal
- mov al, '/'
- stosw
- mov ax, bx ;Month
- mov cl, 5
- shr ax, cl
- and ax, 0Fh
- mov cl, 2
- call WriteDecimal
- pop di
- add di, 12
- push di
- mov bx, [FILE_TIME] ;File time:
- mov ax, bx ;Minutes
- mov cl, 5
- shr ax, cl
- and ax, 3Fh
- mov cx, 2
- call WriteDecimal
- mov al, ':'
- stosw
- mov al, bh ;Hours
- mov cl, 3
- shr al, cl
- sub ah, ah
- sub cl, cl
- call WriteDecimal
- cld
- pop di
- add di, 4
- mov dl, [attrib] ;Display attribute letters
- test dl, 1 ;Read-only
- jz @@L3
- mov al, 'R'
- stosw
- @@L3:
- test dl, 2 ;Hidden
- jz @@L4
- mov al, 'H'
- stosw
- @@L4:
- test dl, 4 ;System
- jz @@L5
- mov al, 'S'
- stosw
- @@L5:
- test dl, 20h ;Archive
- jz @@L6
- mov al, 'A'
- stosw
- @@L6:
- mov al, 186 ;Display divider
- stosw
- mov si, OFFSET pathNSpec ;Display path and filespec
- call DisplayString
- mov di, 158 ;Display total size of displayed files
- mov si, OFFSET totalSize
- call WriteLongDecimal
- mov bx, [top]
- mov di, 160
- cld
- DisplayNext:
- mov ah, [normal] ;Set to inverse video if cursor line
- cmp bx, [cursor]
- jne @@L0
- mov ah, [inverse]
- @@L0:
- cmp bx, [last] ;If done with files,
- jle @@L0a
- mov cx, 16 ;Blank out name area
- jmp SHORT @@L7
- @@L0a:
- mov si, [bx] ;Get table entry for a file
- lodsb ;Get status byte
- test al, TAGGED ;If file has been tagged, display '>'
- mov al, '>'
- jnz @@L1
- mov al, ' '
- @@L1:
- stosw
- mov cx, 9 ;In field of 9,
- @@L2:
- lodsb ;Display filename up to extension
- cmp al, '.'
- je @@L3
- or al, al
- jz @@L6
- @@L2a:
- stosw
- loop @@L2
- @@L3:
- cmp cx, 9 ;Check for special cases of '.', '..'
- je @@L2a
- cmp [byte si-2], '.'
- je @@L2a
- mov al, ' ' ;Else pad with spaces out to 9 chars
- rep stosw
- @@L4:
- mov cx, 6 ;Display extension in field of 6
- @@L5:
- lodsb
- or al, al
- jz @@L7
- stosw
- loop @@L5
- jmp SHORT @@L7
- @@L6:
- add cx, 6 ;Just pad with blanks if no extension
- @@L7:
- mov al, ' '
- rep stosw
- cmp di, 4000 ;Stop at screenful
- je GetCommand
- cmp di, 3872
- jb @@L8
- sub di, 3808 ;Next column
- @@L8:
- add di, 128 ;Next row
- add bx, 2
- jmp DisplayNext
-
- ;Get command
- GetCommand:
- call HideCursor
- mov es, [programSeg]
- mov ah, 8 ;Get keypress
- sub ch, ch
- @@L1:
- inc ch
- int 21h
- or al, al
- jz @@L1
- mov ah, ch ;AH = 2 if aux code, 1 if plain ASCII
- call ToUpper
- mov di, OFFSET CommandKeys ;Look it up, get pointer to routine
- mov cx, NCOMMANDS
- repne scasw
- jne InvalidCommand
- add di, CommandAddrs-CommandKeys-2
- mov bx, [cursor] ;SI -> file record for highlighted file
- mov si, [bx]
- call ShowCursor
- jmp [word di] ;Jump to routine
- InvalidCommand:
- call Beep
- jmp GetCommand
-
- ;********************************* Commands ***********************************
-
- Up:
- sub bx, 2
- jmp SHORT NewLine
-
- Down:
- add bx, 2
- jmp SHORT NewLine
-
- Left:
- sub bx, 48
- jmp SHORT NewLine
-
- Right:
- add bx, 48
- jmp SHORT NewLine
-
- PageUp:
- sub bx, 238
- jmp SHORT NewLine
-
- PageDown:
- add bx, 238
-
- NewLine:
- cmp bx, [last] ;Make sure cursor is still within bounds
- jbe @@L1
- mov bx, [last]
- @@L1:
- cmp bx, OFFSET files
- jae @@L2
- mov bx, OFFSET files
- @@L2:
- cmp bx, [top] ;Slide window if off screen
- jae @@L3
- mov [top], bx
- jmp SHORT @@L4
- @@L3:
- mov ax, bx
- sub ax, 238
- cmp ax, [top]
- jb @@L4
- mov [top], ax
- @@L4:
- mov [cursor], bx
- jmp DisplayFiles
-
- Tag:
- test [byte si], NOT NORMAL_FILE ;Only allow marking of normal files
- jnz @@L1
- xor [byte si], TAGGED
- @@L1:
- jmp DisplayFiles
-
- Go:
- mov [byte inputString], 0 ;Initialize to no user-entered command tail
- Go0:
- lodsb ;Get attribute byte
- mov dx, si ;Join path and file name
- mov si, PATH
- mov di, OFFSET buffer
- call Join
- test al, 10h ;If a directory,
- jz DoExec
- ChangeDir:
- mov dx, OFFSET buffer
- mov ah, 3Bh ;Change to it
- int 21h
- mov [byte PATH], 0 ;No path now
- mov di, FILESPEC ;Read in contents of new directory
- jmp NewDir
- DoExec:
- mov si, dx ;Find extension
- @@L1:
- lodsb
- cmp al, '.'
- je @@L2
- or al, al
- jne @@L1
- jmp SHORT @@L4
- @@L2:
- mov di, OFFSET extensions ;If .EXE, .COM or .BAT, execute it
- mov dx, si
- @@L3:
- mov si, dx
- mov cx, 3
- repe cmpsb
- je @@L5
- sub al, al
- repne scasb
- cmp [byte di], 0
- jne @@L3
- @@L4:
- mov si, OFFSET notExecMsg ;Else error, not an executable file
- jmp DoError
- @@L5:
- call BlankScreen
- mov dx, OFFSET buffer ;If .BAT, need COMMAND.COM, otherwise don't
- cmp [byte di], 0
- jne @@L6
- mov si, OFFSET CC
- label DoEdit near ;Edit function enters here
- mov di, OFFSET EXECCmdLine+1
- call CopyString ;Store '/c ' or '/c <editor> ' to command tail
- mov dl, cl
- mov si, OFFSET buffer ;Append path\file
- call CopyString
- add dl, cl
- mov [EXECCmdLine], dl ;Store length, append CR
- mov [byte di], 13
- mov dx, [comspecOff]
- mov ds, [comspecSeg]
- @@L6:
- cmp [byte cs:inputString], 0 ;If a command tail was entered,
- jz DoDOS
- push ds
- mov ds, [cs:programSeg]
- mov di, OFFSET EXECCmdLine+1
- mov al, ' ' ;Add a space
- stosb
- mov si, OFFSET inputString ;Add command tail
- call CopyString
- inc cl
- add [EXECCmdLine], cl
- mov [byte di], 13
- pop ds
- DoDOS:
- mov cx, bx
- mov bx, (inputString-BOF)/16+1 ;Release unneeded memory
- mov ah, 4Ah
- int 21h
- jc SysErr
- call BlankScreen
- push cx
- mov [cs:temp], sp ;Do EXEC
- mov bx, OFFSET EXECParams
- mov ax, 4B00h
- int 21h
- mov bx, cs ;Restore critical registers
- mov ds, bx
- mov es, bx
- mov ss, bx
- mov sp, [temp]
- pop bx
- jnc @@L2
- mov si, OFFSET sysErrMsg ;EXEC error
- cmp al, 8 ;If return code = 8, no room
- jne @@L1
- mov si, OFFSET noExecRoomMsg
- @@L1:
- jmp DoError
- @@L2:
- mov [byte EXECCmdLine], 0 ;Tidy up
- jmp Restart0
-
- SysErr:
- mov si, OFFSET sysErrMsg
- DoError:
- call Error
- jmp DisplayFiles
-
- GoCL:
- mov si, OFFSET commandTailMsg ;Prompt for command tail
- call Query
- mov si, [bx]
- jmp Go0
-
- DOS:
- mov dx, [comspecOff]
- mov ds, [comspecSeg]
- jmp DoDOS
-
- Edit:
- lea dx, [si+1] ;Join path and file name
- mov si, PATH
- mov di, OFFSET buffer
- call Join
- mov si, OFFSET editor ;Invoke editor
- mov [byte inputString],0
- jmp DoEdit
-
- Copy:
- mov [byte CMDR], COPYVAL ;Set Copy/Move/Delete/Remove key to Copy
- jmp SHORT DoCopy
-
- Delete:
- mov [byte CMDR], DELETEVAL ;Set Copy/Move/Delete/Remove key to Delete
- jmp SHORT DoCMDR
-
- Move:
- mov [byte CMDR], MOVEVAL ;Set Copy/Move/Delete/Rename key to Move
-
- DoCopy:
- mov si, OFFSET DestMsg ;If Copy or Move, prompt for destination
- call Query
- mov di, si
- mov [byte si], '\' ;Append '\'
- inc si
- mov [temp], si
- cmp [byte CMDR], MOVEVAL
- jne DoCMDR
- mov ax, [word FILESPEC] ;If Move to same drive,
- mov dx, [word inputString]
- cmp ah, ':'
- je @@L1
- cmp dh, ':'
- jne @@L2
- @@L1:
- cmp ax, dx
- jne DoCMDR
- @@L2:
- mov [byte CMDR], RENAMEVAL ; do Rename instead (much faster)
- DoCMDR:
- mov bp, OFFSET files - 2 ;For each file
- CMDRNext:
- add bp, 2
- cmp bp, [last]
- jbe @@L0
- jmp GetFileRecords
- @@L0:
- mov si, [bp] ;Skip if not tagged
- lodsb
- test al, TAGGED
- jz CMDRNext
- xor [byte si-1], TAGGED ;Else untag
- mov dx, si
- mov si, PATH ;Source path\filename -> sourceFileSpec
- mov di, OFFSET sourceFileSpec
- call Join
- cmp [byte CMDR], DELETEVAL ;If not Deleting
- je @@L4
- mov si, dx ;Append current file's name to destination path
- mov di, [temp]
- call CopyString
- cmp [byte CMDR], RENAMEVAL ;If Rename, do it
- jne @@L2
- label DoRename near
- mov dx, OFFSET sourceFileSpec
- mov di, OFFSET inputString
- mov ah, 56h
- int 21h
- jnc @@L1
- mov dx, di ;If rename failed, try deleting target name
- mov ah, 41h
- int 21h
- jnc DoRename ; and try again
- jmp SHORT CantOpen ;If delete failed, abort
- @@L1:
- jmp CMDRNext
- @@L2:
- mov dx, OFFSET sourceFileSpec ;Copy or Move: open source, dest files
- mov ax, 3D00h
- int 21h
- jc CantOpen
- mov [sourceHandle], ax
- sub cx, cx
- mov dx, OFFSET inputString
- mov ax, 3C00h
- int 21h
- jc CantOpen
- mov [destHandle], ax
- @@L3:
- mov bx, [sourceHandle] ;Read a bufferful
- mov cx, 512
- mov dx, OFFSET buffer
- mov ah, 3Fh
- int 21h
- jc ReadError
- mov bx, [destHandle] ;Write it
- mov cx, ax
- mov ah, 40h
- int 21h
- jc WriteError
- cmp ax, cx
- jb FullError
- cmp cx, 512 ;Loop until done
- je @@L3
- mov ah, 3Eh ;Close files
- mov bx, [sourceHandle]
- int 21h
- mov bx, [destHandle]
- int 21h
- cmp [CMDR], MOVEVAL ;If Move, now do Delete
- jne @@L1
- @@L4:
- mov bx, OFFSET sourceFileSpec ;Delete file
- mov ah, 41h
- int 21h
- jnc @@L1
-
- CantOpen:
- mov si, OFFSET cantOpenMsg
- jmp DoError
- ReadError:
- mov si, OFFSET readMsg
- jmp DoError
- WriteError:
- mov si, OFFSET writeMsg
- jmp DoError
- FullError:
- mov si, OFFSET fullMsg
- jmp DoError
-
- NewFilespec:
- mov si, OFFSET newSpecMsg ;Prompt for new filespec
- call Query
- inc al
- mov [FILESPEC-2], al ;Store count of chars
- mov si, OFFSET inputString
- mov di, FILESPEC
- call CopyString ;Copy new filespec to command tail area
- mov [byte di], 0Dh ;Append CR
- jmp NewSpec ;Process new filespec
-
- Rename:
- lea dx, [si + 1] ;Join path and current name
- mov si, PATH
- mov di, OFFSET sourceFileSpec
- call Join
- mov si, OFFSET newNameMsg ;Prompt for new name of file or directory
- call Query
- jmp DoRename
-
- Drive:
- mov si, OFFSET newDriveMsg ;Prompt for letter of drive to change to
- call QueryChar
- sub al, 'A'
- mov dl, al
- mov ah, 0Eh
- int 21h
- cmp dl, al ;Ask again if that drive doesn't exist
- jb @@L1
- mov si, OFFSET badDriveMsg
- jmp DoError
- @@L1:
- mov [byte FILESPEC-2], 0 ;If successful, start with default filespec
- jmp NewSpec
-
- Sort:
- ;
- ;Sort algorithm:
- ; 1) make up array of records {pointer to field to sort | tag}, one for each
- ; file, in 'buffer'.
- ; 2) bubble-sort these records
- ; 3) copy file record pointers in 'files' to 'buffer' in order of sorted tags
- ; 4) copy file record pointers back to 'files' in new order
- ;
- mov si, OFFSET sortMsg ;Prompt for sort field
- call QueryChar
- cmp al, 'N' ;Check for legal sort field option
- je Sort0
- cmp al, 'E'
- je Sort0
- cmp al, 'D'
- je Sort0
- mov si, OFFSET genErrorMsg
- jmp DoError
- Sort0:
- mov [keepSorted], al ;Remember for later resorting after EXEC
- mov dl, al
- sub dh, dh ;DH = tag (position of file in current order)
- mov di, OFFSET buffer
- mov bx, OFFSET files
- @@L1:
- mov si, [bx] ;Find field to sort: get pointer to record
- @@L1a:
- inc si
- mov cx, si
- cmp dl, 'N' ;If Name, already pointing at it
- je @@L4
- sub ah, ah ;If Date, find null at end of name
- cmp dl, 'E' ;If Ext find '.' or end of name
- jne @@L2
- cmp [byte si], '.' ;'.' and '..' are special cases
- je @@L1a
- mov ah, '.'
- @@L2:
- lodsb
- or al, al
- je @@L3
- cmp al, ah
- jne @@L2
- @@L3:
- dec si ;If Ext, back up to '.' or null
- cmp dl, 'E'
- je @@L4
- add si, 3 ;If Date, advance to date field
- @@L4:
- mov ax, si ;Store pointer to field to sort
- stosw
- mov al, dh ;Store tag
- stosb
- inc dh ;Bump tag
- add bx, 2 ;Loop until no more files
- cmp bx, [last]
- jbe @@L1
- DoSort:
- lea bp, [di-3] ;BP -> last
- push bp
- @@L0:
- mov bx, OFFSET buffer ;Do bubble sort
- @@L1:
- mov si, [bx]
- cmp [word si-1], '.' ;Leave '.' and '..' alone
- je @@L4
- mov di, [bx+3]
- cmp dl, 'D' ;If sorting Dates, compare one word
- jne @@L2
- cmpsw
- jmp SHORT @@L3
- @@L2:
- mov cx, -1 ;Else compare bytes until not equal
- repe cmpsb
- @@L3:
- jbe @@L4 ;If first field > second
- mov ax, [bx] ;Exchange field pointers and tags
- xchg ax, [bx+3]
- mov [bx], ax
- mov al, [bx+2]
- xchg al, [bx+5]
- mov [bx+2], al
- @@L4:
- add bx, 3 ;Loop until no more files this pass
- cmp bx, bp
- jb @@L1
- sub bp, 3
- cmp bp, OFFSET buffer ;Loop until no more passes
- jne @@L0
- OrderByTags:
- mov di, OFFSET buffer ;Arrange file pointers in order of tags
- mov si, OFFSET files
- pop bp
- @@L1:
- mov bl, [di+2] ;Get tag
- sub bh, bh
- add bx, bx
- mov ax, [bx+si] ;Get file ptr associated with that tag
- stosw ;Store in place of field pointer in sort buffer
- inc di
- cmp di, bp
- jbe @@L1
- mov si, OFFSET buffer
- mov di, OFFSET files
- @@L2:
- movsw ;Copy file pointers back in new order
- inc si
- cmp di, [last]
- jbe @@L2
- jmp DisplayFiles
-
- Help:
- call BlankStatus ;Display help on status line
- mov si, OFFSET helpMsg
- call DisplayString
- mov ah, 8
- int 21h
- jmp DisplayFiles
-
- Exit:
- call BlankScreen
- mov ax, 4C00h ;Bye
- int 21h
-
- ;******************************* Subroutines **********************************
-
- WriteLongDecimal:
- ;
- ;Display 4-byte integer
- ; IN: SI -> number, DI -> display address of least significant digit
- ; OUT: none
- ;USED: AX CX DX
- push cx
- push dx
- push di
- mov ax, [si]
- mov dx, [si + 2]
- mov cx, 10000 ;Divide by 10000, show quotient|remainder
- div cx
- xchg ax, dx
- or dx, dx
- jz @@L1
- mov cl, 4
- call WriteDecimal
- mov ax, dx
- @@L1:
- sub cl, cl
- call WriteDecimal
- pop di
- pop dx
- pop cx
- ret
-
- WriteDecimal:
- ;
- ;Display a decimal number in inverse video, writing digits backwards from right.
- ; IN: AX = number, CL = field width with leading 0s (no leading 0s if CL = 0)
- ; ES:DI -> Video RAM where rightmost digit will go
- ; OUT: AH = [inverse], DI -> left of first digit
- ;USED: AL, CX
- push bx
- push dx
- std
- mov bx, 10
- sub ch, ch
- @@L1:
- sub dx, dx ;Get a digit
- div bx
- xchg ax, dx ;Write it to display, right to left
- add al, '0'
- mov ah, [inverse]
- stosw
- xchg ax, dx
- cmp cx, 0 ;If CX > 0, loop even if AX = 0
- jg @@L2
- or ax, ax ;Else loop only if AX > 0 (more digits left)
- jz @@L3
- @@L2:
- loop @@L1
- @@L3:
- pop dx
- pop bx
- mov ah, [inverse]
- Ret1:
- ret
-
- DisplayString:
- ;
- ;Display string on status line.
- ; IN: SI -> string (null-terminated), ES:DI -> status line, AH = attribute
- ; OUT: DI is advanced past end of string
- ;USES: AL SI
- @@L1:
- lodsb
- or al, al
- jz Ret1
- stosw
- jmp @@L1
-
- DisplayInputString:
- ;
- ;Same as above but show cursor at end of line
- ; IN, OUT, USES -- see above
- push bx
- push dx
- call DisplayString
- mov dx, di ;Set cursor to end of printed string
- add dx, 2
- shr dl, 1
- sub dh, dh
- mov ah, 2
- sub bx, bx
- int 10h
- pop dx
- pop bx
- ret
-
-
- Error:
- ;
- ;Beep, display string on status line and wait for keypress (any key)
- ; IN: SI -> string
- ; OUT: ES -> program segment
- ;USED: AX
- call Beep
- call BlankStatus
- call DisplayString ;Display error string
- mov si, OFFSET ErrorMsg ;Display 'Press any key' message
- call DisplayString
- mov ah, 8
- int 21h
- mov es, [programSeg]
- ret
-
- Query:
- ;
- ;Prompt for string input on status line
- ; IN: SI -> message
- ; OUT: SI -> null at end of ASCIIZ string input, AX = length (excluding null)
- ;USED: none
- push bx
- push cx
- push dx
- push di
- push es
- call BlankStatus
- call DisplayInputString
- mov cx, 80 ;Get input
- mov dx, OFFSET inputString
- mov si, dx
- sub bx, bx
- mov ah, 3Fh
- int 21h
- sub ax, 2
- add si, ax
- mov [byte si], 0 ;Null-terminate it
- pop es
- pop di
- pop dx
- pop cx
- pop bx
- ret
-
- QueryChar:
- ;
- ;Prompt for single character input
- ; IN: SI -> message
- ; OUT: AL = character (lower case converted to upper)
- ;USED: AH
- push es
- call BlankStatus
- call DisplayInputString ;Display string
- mov ah, 8 ;Get char
- int 21h
- call ToUpper
- pop es
- ret
-
- BlankStatus:
- ;
- ;Clear top line of display to inverse video
- ; IN: none
- ; OUT: ES = video segment, DI = 0
- ;USED: AX CX
- mov ax, [displaySegment]
- mov es, ax
- sub di, di
- mov al, ' '
- mov ah, [inverse]
- mov cx, 80
- rep stosw
- sub di, di
- ret
-
- Join:
- ;
- ;Copy counted path, then ASCIIZ file name to buffer and null-terminate
- ; IN: SI -> path, DX -> file, DI -> destination
- ; OUT: DI -> null at end of copied string, CX = total chars excluding null
- ;USED: none
- push ax
- push si
- lodsb ;Get count of chars in path (a counted string)
- sub ah, ah
- mov cx, ax
- rep movsb ;Copy it to destination
- mov cx, ax
- mov si, dx ;Now copy file name (null-terminated)
- call CopyString
- add cx, ax ;Sum string counts -> CX
- mov [byte di], 0 ;Null-terminate the result
- pop si
- pop ax
- ret
-
- CopyString:
- ;
- ;Copy null-terminated string.
- ; IN: SI -> string, DI -> destination
- ; OUT: CX = length (excluding null), DI -> terminating null of copied string
- ;USED: AL
- mov cx, -1
- @@L1:
- lodsb ;Copy string
- stosb
- or al, al ;Until null at end is encountered
- loopnz @@L1 ;Accumulate count of chars
- neg cx ;Adjust count
- sub cx, 2
- dec di ;DI -> terminating null
- ret
-
- HideCursor:
- ;
- ;Move cursor off bottom of screen
- ; IN: none
- ; OUT: none
- ;USED: AH
- push bx
- push dx
- mov dx, 1900h
- DoCursor:
- sub bh, bh
- mov ah, 2
- int 10h
- pop dx
- pop bx
- ret
-
- ShowCursor:
- ;
- ;Put cursor back at 0,0
- ; IN: none
- ; OUT: none
- ;USED: AH
- push bx
- push dx
- sub dx, dx
- jmp DoCursor
-
- Beep:
- ;
- ;Output a bell char
- ; IN: none
- ; OUT: none
- ;USED: AH DL
- mov dl, 7
- mov ah, 2
- int 21h
- ret
-
- BlankScreen:
- ;
- ;Clear screen to original color and home cursor
- ; IN: none
- ; OUT: none
- ;USED: AX
- push cx
- push es
- push di
- mov es, [cs:displaySegment] ;Blank screen
- sub di, di
- mov al, ' '
- mov ah, [original]
- mov cx, 25 * 80
- rep stosw
- pop di
- pop es
- pop cx
- ret
-
- ToUpper:
- ;
- ;Convert lower to upper case
- ; IN: AL = char
- ; OUT: AL = char
- ;USED: none
- cmp al, 'a'
- jb @@L1
- cmp al, 'z'
- ja @@L1
- add al, 'A'-'a'
- @@L1:
- ret
-
- ;********************************** Data **************************************
-
-
- ;Command dispatch table: aux,2 or ASCII,1 paired to command routine addresses
-
- commandKeys db 72,2, 80,2, 75,2, 77,2, 73,2, 81,2, 'T',1, 13,1, 'C',1
- db 'D',1, 'M',1, 'R',1, 'E',1, 'F',1, 'V',1, 'S',1
- db 60,2, 10,1, 59,2, 27,1
- commandAddrs dw Up, Down, Left, Right, PageUp, PageDown, Tag, Go, Copy
- dw Delete, Move, Rename, Edit, NewFilespec, Drive, Sort
- dw DOS, GoCL, Help, Exit
- NCOMMANDS EQU (commandAddrs-commandKeys)/2
-
-
- ;Strings
-
- helpMsg db 'Copy Delete Edit Filespec Move Ren Sort '
- db 'Tag driVe Enter=cd/run F2=DOS Esc=exit',0
- helpF1 db 'Help F1',186,0
- noFilesMsg db 'No matching files or invalid path',0
- noRoomMsg db 'Out of room$'
- badPathMsg db 'Bad path',0
- sysErrMsg db 'System error',0
- cantOpenMsg db "Can't open file",0
- writeMsg db 'Write error',0
- fullMsg db 'Disk full',0
- readMsg db 'Read error',0
- notExecMsg db 'Not a directory or executable file',0
- badDriveMsg db "Drive doesn't exist",0
- genErrorMsg db 'Error',0
- tooManyMsg db 'Too many files',0
- noExecRoomMsg db 'Not enough memory',0
- ErrorMsg db '. Press any key.',0
- destMsg db 'Where to?',0
- newSpecMsg db 'New filespec:',0
- newDriveMsg db 'New drive:',0
- sortMsg db 'Sort on: Name Ext Date',0
- newNameMsg db 'New name:',0
- commandTailMsg db 'Command tail:',0
- dirMsg db '<DIR>',0
- extensions db 'EXECOMBAT',0
- starDotStar db '*.*',0
- original db ? ;Original screen color to restore on exit
- inverse db 70h ;Black on white
- normal db 17h ;White on blue
- editor db '/C E ', 12 dup (0)
- cc db '/C ',0
- comspec db 'COMSPEC='
-
-
- ;EXEC function parameter block
-
- EXECParams dw 0
- EXECCmdLineOff dw OFFSET EXECCmdLine
- programSeg dw 0
- dw -1, -1 , -1 , -1
-
- EXECCmdLine db 0, 80 dup (?)
- sourceFileSpec EQU EXECCmdLine ;Second use for this space during Copy etc.
-
-
- ;Variables, buffers
-
- dw 128 dup (?) ;Stack (here for protection during EXEC)
- stackEnd:
- keepSorted db ? ;Holds sort subcommand char if this dir sorted
- CMDR db ? ;Key for Copy/Move/Delete/Rename actions
- attrib db ? ;File attribute byte
- totalSize dw ?, ? ;Sum of file sizes
- sourceHandle dw ? ;Source handle for Copy, etc.
- destHandle dw ? ;Destination handle for Copy etc.
- cursor dw ? ;Position in 'files' of highlighted file
- last dw ? ;Position in 'files' of last file in directory
- top dw ? ;Position in 'files' of file at top of screen
- temp dw ? ;Holds SP during EXEC, other uses
- comspecSeg dw ? ;Segment of environment
- comspecOff dw ? ;Offset of 'C:\COMMAND.COM' in environment
- displaySegment dw ? ;Segment of display RAM
- pathNSpec db 80 dup (?) ;Default path and current filespec for display
- DTA db 64 dup (?) ;Disk Transfer Area
- inputString db 80 dup (?) ;String returned by 'Query', other uses
- files dw NFILES dup (?) ;Array of pointers to file records
- fileRecords db 80*NFILES dup (?) ;File records: attrib/name/time/date
- buffer db 512 dup (?) ;Buffer for Copy, etc.
-
- EOF:
- end Start