home *** CD-ROM | disk | FTP | other *** search
- PAGE 84,132
- ;-----------------------------------------------------------------------------|
- ; ---- ScanSoft(tm) SORTDIR (C)1991 Cornel Huth -- All Rights Reserved ---- |
- ;-----------------------------------------------------------------------------|
- ; program: SORTDIR.ASM |
- ; version: 1.02 COPYRIGHT 1991 Cornel Huth |
- ; by: Cornel Huth 6402 Ingram Rd/San Antonio, TX/78238 |
- ; date: 09-Sep-91 |
- ; function: sort current directory |
- ; caller: COMMAND |
- ; use: |
- ; |
- ; C>SD [options] * sort current directory by filename [options] |
- ; options: |
- ; SD /e * by ext.filename (default) |
- ; SD /n * by filename.ext |
- ; SD /h * help with anything other CLP |
- ;-----------------------------------------------------------------------------|
- ;NOTES: |
- ;Code requires DOS 3.2+ for IOCTL functions |
- ;Requires MASM 5.1 to assemble |
- ;Should work on any DOS machine since everything is DOS done |
- ;User documentation found, where else, in the User Documentation |
- ;LIMITATIONS: (some could be considered benifits) |
- ;Operates on current drive/current directory only |
- ;Will not sort entries prior to any hidden, system, or subdirectory entries |
- ;Root directory must lie in the first 64K sectors of the DOS drive(no problem)|
- ;FAT must be less than 64K (no problem) |
- ;Maximum of 1792 directory entries per subdirectory (seems like enough) |
- ;Sort source not included (how does that grab you?) |
- ;-----------------------------------------------------------------------------|
- ;Being a programmer I'm always deleting working files. I like to keep my subs |
- ;packed and files grouped by extension. 32MB+ parts made Norton DS unusable so|
- ;PCTools 4.22 had been used to sort subdirs on large DOS 3.31 parts. HOWEVER, |
- ;in writing this code (using PCT422 for direct disk access) I noticed PCT422 |
- ;becomes real flakey (try accessing, say, cluster# 18,000, or even 10,000)-- |
- ;--a real good reason to have a dir sort program written for large partitions.|
- ;One reason for this is that previous DOS versions had a total sector count |
- ;indicating the number of sectors on a drive. If it was 4086 or less then the |
- ;FAT used 12-bit entries, 4087 or more, 16-bit entries. In DOS versions that |
- ;allow large partitions, the total sector count is not large enough to express|
- ;sector counts above 64K. What these do then is set the regular total sector |
- ;count to 0 and in another location set a 32-bit entry to the total sectors. |
- ;What is probably happening is that programs unaware of the new DOS tactic is |
- ;checking for a total sector count less than 4087 (which it is on large parts)|
- ;and if so, assumes a 12-bit FAT! Some programs see the 0 for what it is, |
- ;somewhat, and indicate that the FAT scheme is unknown. |
- ;-----------------------------------------------------------------------------|
- ; NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: |
- ;-----------------------------------------------------------------------------|
- ; >>>>>>>>>>>>>>>>> THIS SOURCE CODE IS *NOT* PUBLIC DOMAIN <<<<<<<<<<<<<<<<< |
- ;-----------------------------------------------------------------------------|
- ;I allow you to modify this source ONLY for your personal, non-commercial use |
- ;You may NOT distribute this source if altered in any way |
- ;You may NOT distribute any directory sorting program derived from this source|
- ;If you can't abide by these terms then don't use any of this code. |
- ;-----------------------------------------------------------------------------|
- ;C>masm sd.asm;
- ;C>link /cp:1 sd,sd.exe; (MUST LINK WITH /cp:1)
- ;-----------------------------------------------------------------------------|
- ;1.00-chh 2-Sep-91 Initial release
- ;1.01-chh 6-Sep-91 A1* Change entries-to-sort parm (CX) of Quiksort to position-
- ;of-last-sort-item since we're not starting sort (necessarily) at item 1
- ;1.02-chh 9-Sep-91 B0* Change stack to 1024 bytes from 512
- ;B1* Move DOS 1 ret setup to start of program for correct PSP segment push
- ;B2* Increase max directory entries to 1792 and correct too many clusters check
- ;since previous code check based on 1 sector/cluster
- ;B3* Change default sort order to ext.filename
- ;B4* Floppies will have byte F6h in the root directory from the format--need to
- ;explicitly check for the entry being unused (byte0=0) and not assume that
- ;if it is unused that all the bytes will be that way. Thanks K.B.
- ;-----------------------------------------------------------------------------|
-
- WPTR EQU <WORD PTR>
- BPTR EQU <BYTE PTR>
-
- STDIN EQU 0
- STDOUT EQU 1
- STDERR EQU 2
-
- MAXDIR EQU 1792 ;B2* max directory entries per subdir (1792=56K)
- ;(MAXDIR*32 should be evenly divisble by cluster size in bytes)
- ;for all cluster size from 512,1024,2048,4096,8192 the full
- ;1792 entries are available, 16K clusters can have 1536 avail
-
- DeviceParms STRUC ;DEVICE PARMS STRUCTURE
- dpSpecFunc db 1 DUP (?) ;special functions
- dpDevType db 1 DUP (?) ;device type
- dpDevAttr dw 1 DUP (?) ;device attribute
- dpCylinders dw 1 DUP (?) ;number of cylinders
- dpMediaType db 1 DUP (?) ;media type
- ;BPB follows
- dpBytesSector dw 1 DUP (?) ;bytes per sector
- dpSectorsClust db 1 DUP (?) ;sectors per cluster
- dpResSectors dw 1 DUP (?) ;reserved sectors
- dpFATs db 1 DUP (?) ;number of FATs
- dpRootDirEnts dw 1 DUP (?) ;root directory entries
- dpSectors dw 1 DUP (?) ;if 0 then > 32MB DOS drive, use dpHugeSectors
- dpMedia db 1 DUP (?) ;media byte
- dpFATsecs dw 1 DUP (?) ;sectors used by each FAT
- dpSectorsTrack dw 1 DUP (?) ;sectors per track
- dpHeads dw 1 DUP (?) ;heads
- dpHiddenSecs dd 1 DUP (?) ;hidden sectors
- dpHugeSectors dd 1 DUP (?) ;number of sectors if dpSectors=0
- DeviceParms ENDS
-
- rwBlock STRUC ;READ/WRITE TRACK ON LOGICAL DRIVE STRUCTURE
- rwSpecFunc db 1 DUP (?)
- rwHead dw 1 DUP (?)
- rwCylinder dw 1 DUP (?)
- rwFirstSector dw 1 DUP (?)
- rwSectors dw 1 DUP (?)
- rwBuffer dd 1 DUP (?)
- rwBlock ENDS
-
- DirEntry STRUC ;DIRECTORY ENTRY STRUCTURE
- deName db 8 DUP (?)
- deExtension db 3 DUP (?)
- deAttributes db 1 DUP (?)
- deReserved db 10 DUP (?)
- deTime dw 1 DUP (?)
- deDate dw 1 DUP (?)
- deStartCluster dw 1 DUP (?)
- deFileSize dd 1 DUP (?)
- DirEntry ENDS
-
- DOSSEG
- .MODEL SMALL
- .STACK 1024 ;B0* more stack for the expand sort buffer
-
- .DATA? ;simplified segment directives use DGROUP offset
-
- MajorV db 1 DUP (?) ;DOS version
- MinorV db 1 DUP (?) ;-
- INT24error dw 1 DUP (?) ;DOS fatal error
- INT24seg dw 1 DUP (?) ;original INT24 vector
- INT24off dw 1 DUP (?) ;-DOS restores on program exit
- INT23seg dw 1 DUP (?) ;original INT23 vector
- INT23off dw 1 DUP (?) ;-DOS restores on program exit
- INT1Bseg dw 1 DUP (?) ;original INT1B vector
- INT1Boff dw 1 DUP (?) ;-must be restored before exiting (BIOS vector)
- INT00seg dw 1 DUP (?) ;original INT00 vector
- INT00off dw 1 DUP (?) ;-must be restored before exiting (BIOS vector)
- PSPseg dw 1 DUP (?) ;PSP segment at load time
- SegBuffFAT dw 1 DUP (?) ;segment of buffer for FAT
- SegBuffFAT2 dw 1 DUP (?) ;segment of buffer for FAT2
- FATtype db 1 DUP (?) ;12 or 16 for FAT bit size
- CurrDrive db 1 DUP (?) ;current DOS drive (default)
- CurrDir db 64 DUP (?) ;current DOS directory
- StartCluster dw 1 DUP (?) ;starting cluster of subdirectory
- ClusterList dw MAXDIR/16/1 DUP (?) ;cluster link list (say, 112)
- ;(1792 entries/16 ent/sec/clust (1 sec/cluster))
- ClusterListOF dw 1 DUP (?) ;end of link marker overflow
- FATsector dw 1 DUP (?) ;logical DOS sector of first FAT
- ROOTsector dw 1 DUP (?) ;logical DOS sector of root directory
- DATAsector dw 1 DUP (?) ;logical DOS sector of data start
- BytesCluster dw 1 DUP (?) ;bytes per cluster
- LOGSEC dd 1 DUP (?) ;logical DOS sector (32-bit)
- DOScylinder dw 1 DUP (?) ;format for IOCTL Read Track
- DOShead dw 1 DUP (?) ; "
- DOSsector dw 1 DUP (?) ; "
-
- lo dw 1 DUP (?) ;Quiksort data
- hi dw 1 DUP (?)
- reclen dw 1 DUP (?)
- cstart dw 1 DUP (?)
- cbytes db 1 DUP (?)
- db 1 DUP (?) ;even it up
- sptr dw 1 DUP (?)
- Swap1 dw 1 DUP (?) ;->start of record to swap
- Swap2 dw 1 DUP (?) ;->start of record to swap
- TmpReg dw 1 DUP (?)
-
- rBlock rwBlock <> ;IOCTL read track info
- wBlock rwBlock <> ;IOCTL write track info
- BuffDeviceParms DeviceParms <> ;device parameters
- EVEN
- BuffDirSort DirEntry 1+MAXDIR+1 DUP (<>) ;directory entry slots (@#$!)
- ;1 first for Quiksort work space
- ;1 extra for count check
- .DATA
-
- IDmsg db 'SORTDIR 1.02 (C) 1991 Cornel Huth - All Rights Reserved',13,10
- IDmsgL =$-IDmsg
-
- CRLF db 13,10
- CurrDrvMsgPre db 'Sorting '
- CurrDrvMsg db 'Z:\'
- CurrDrvMsgPreL =$-CurrDrvMsgPre
-
- MSortInfo db 'Entries skipped/sorted ' ;sorted excludes deleted entries
- SortInfo db 9 DUP (' ') ;max 4 +'/'+ 4
- MSortInfoL =$-MSortInfo
-
- EDoneNo =0
- EDone db 'ok'
- EDoneL =$-EDone
- EDOSNo =1
- MinDOS EQU 0314h
- EDOS db 'Requires DOS 3.20+'
- EDOSL =$-EDOS
- db '$' ;for DOS 1 message
- EUnkSwitchNo =2
- EUnkSwitch db '* Invalid switch. Use: C>sd [/<en>]',13,10,13,10
- db 9,'On current drive/directory sort directory by:',13,10
- db 9,'/e ext.filename (default)',13,10 ;B3*
- db 9,'/n filename.ext',13,10
- EUnkSwitchL =$-EUnkSwitch
- EInvalidDrvNo =3
- EInvalidDrv db 'Invalid drive' ;remote drive
- EInvalidDrvL =$-EInvalidDrv
- EAccessNo =4
- EAccess db 'Cannot access media' ;r/w fault
- EAccessL =$-EAccess
- EUnkDeviceNo =5
- EUnkDevice db 'Unknown DOS device' ;e.g., 8-in floppy
- EUnkDeviceL =$-EUnkDevice
- ERootFarNo =6
- ERootFar db 'Root directory not within first 64K DOS sectors'
- ERootFarL =$-ERootFar
- EInvalidFuncNo =7
- EInvalidFunc db 'Program function not available' ;stub message
- EInvalidFuncL =$-EInvalidFunc
- ENoFATmemoryNo =8
- ENoFATmemory db 'Not enough memory for FAT'
- ENoFATmemoryL =$-ENoFATmemory
- EFATnoMatchNo =9
- EFATnoMatch db 'File Allocation Tables do not match'
- EFATnoMatchL =$-EFATnoMatch
- EInvalidDTANo =10
- EInvalidDTA db 'Unknown DOS DTA structure';CDS not 100% compat in DRDOS-5
- EInvalidDTAL =$-EInvalidDTA ;so use DTA structure after FindF
- EOS2No =11 ;to locate starting cluster of SD
- EOS2 db 'Cannot operate in OS/2 DOS box'
- EOS2L =$-EOS2
- EMathNo =12
- EMath db 'Math overflow'
- EMathL =$-EMath
- EFATlinkNo =13
- EFATlink db 'Too many file entries or FAT link corrupt' ;less harsh
- EFATlinkL =$-EFATlink
-
- EVEN
- ErrMsgW dw EDone,EDOS,EUnkSwitch,EInvalidDrv,EAccess,EUnkDevice
- dw ERootFar,EInvalidFunc,ENoFATmemory,EFATnoMatch,EInvalidDTA
- dw EOS2,EMath,EFATLink
-
- ErrMsgL db EDoneL,EDOSL,EUnkSwitchL,EInvalidDrvL,EAccessL,EUnkDeviceL
- db ERootFarL,EInvalidFuncL,ENoFATmemoryL,EFATnoMatchL,EInvalidDTAL
- db EOS2L,EMathL,EFATLinkL
-
- ValidDevices db 0,1,2,5,7,8 ;320/360,1.2,720,HD,1.44,2.88
- ValidDevicesL =$-ValidDevices ;device types handled
-
- SortOptions db 'EN' ;B3* options
- SortOptionsL =$-SortOptions
- SortOrder db 'E'
-
- ThisDir db '.',0 ;THIS subdirectory filename
-
- Trap00 db 0 ;=1 then INT00 has been revectored
- Trap1B db 0 ;=1 then INT1B has been revectored
- Trap23 db 0 ;=1 then INT23 has been revectored
- Trap24 db 0 ;=1 then INT24 has been revectored
-
- .CODE
-
- Bail: sub bh,bh
- push bx ;bail to DOS w/message and exitcode
- sub ch,ch
- mov cl,[bx+ErrMsgL]
- shl bl,1
- mov dx,[bx+ErrMsgW]
- mov bx,STDOUT
- mov ah,40h
- int 21h
- sub bl,bl
- cmp bl,Trap1B ;changed INT1B vector?
- je @F ;no
- call INT1Bswitch ;yes,restore (INT23/24 restored by DOS)
- @@: sub bl,bl
- cmp bl,Trap00 ;changed INT00 vector?
- je @F ;no
- call INT00switch ;yes,restore
- @@: pop ax
- mov ah,4Ch
- int 21h
-
- ;-----------------------
- BailDOS1: mov dx,OFFSET EDOS ;bail back to DOS 1
- mov ah,9
- int 21h
- retf
-
- ;=======================
- Start: push ds ;B1* DOS 1 exit return PSP:0
- sub ax,ax
- push ax
-
- mov ax,DGROUP
- mov ds,ax
- mov bx,es
- mov PSPseg,bx
- mov es,ax
- cli
- mov ss,ax
- mov sp,OFFSET STACK
- sti ;ds=es=ss=DGROUP
- ASSUME ds:DGROUP,es:DGROUP,ss:DGROUP
-
-
- ;-----------------------CHECK DOS VERSION
- mov ah,30h
- int 21h
- cmp al,2
- jb BailDOS1 ;DOS 1 bail
-
- mov MajorV,al
- mov MinorV,ah
- cmp al,HIGH MinDOS
- mov bl,EDOSNo ;error message number
- ja @F ;major above min
- jb Bail ;major below min
- cmp ah,LOW MinDOS
- jb Bail ;minor below min
-
- @@: ;-----------------------SHOW PROGRAM ID
- ID01: mov dx,OFFSET IDmsg
- mov cx,IDmsgL
- mov bx,STDOUT
- mov ah,40h
- int 21h
- cmp MajorV,10h ;OS/2 DOS box?
- jb @F ;no
- mov bl,EOS2No
- jmp Bail
-
- @@: ;-----------------------DRIVE RESET
- DR01: mov ah,0Dh
- int 21h
-
- @@: ;-----------------------CHECK COMMAND LINE PARMS
- CL01: mov si,80h
- mov ds,PSPseg ;ds=PSP
- cld
- lodsb
- or al,al ;anything?
- jz CL04 ;no
-
- CL02: lodsb
- cmp al,13 ;CR then done
- je CL04
- cmp al,32 ;skip anything space or below
- jbe CL02
- cmp al,'/' ;option must lead with slash
- jne CL03
- lodsb ;we expect only 1 character
- and al,255-32 ;upper case it
-
- mov cx,es ;load ds=DGROUP
- mov ds,cx
-
- mov di,OFFSET SortOptions
- mov cx,SortOptionsL
- repne scasb ;repeat until found or not
- mov SortOrder,al ;use upper case
- je @F ;found
-
- CL03: mov cx,es ;load ds=DGROUP on bad switch leader
- mov ds,cx
- mov bl,EUnkSwitchNo
- jmp Bail
-
- CL04: mov ax,es ;load ds=DGROUP on no parms
- mov ds,ax
-
- ;@@: ;-----------------------VECTOR INT24 TO LOCAL HANDLER
- ; ;Not used, let COMMAND query what to do since INT24 will occur
- ; ;only using the non-IOCTL (which are used only to read drive)
- ; ;INT1B/00 vectors not changed until after the non-IOCTL reads
- ;INT24trap: mov bl,1
- ; call INT24switch ;DOS restores on exit
-
- @@: ;-----------------------VECTOR INT23 TO LOCAL HANDLER
- INT23trap: mov bl,1
- call INT23switch ;DOS restores on exit
-
- @@: ;-----------------------GET DEFAULT DRIVE
- GetDrv: mov ah,19h
- int 21h
- inc ax ;0=A,1=B,2=C,...
- mov CurrDrive,al ;1=A,2=B,3=C,...
-
- @@: ;-----------------------IS DRIVE REMOTE
- ChkRemote: mov bl,CurrDrive
- mov ax,4409h
- int 21h
- test dx,1000h ;bit 12 drive is remote
- jz @F ;local drive
- mov bl,EInvalidDrvNo
- jmp Bail
-
- @@: ;-----------------------GET CURRENT DIRECTORY
- GetDir: mov dl,CurrDrive
- mov si,OFFSET CurrDir
- mov ah,47h
- int 21h
-
- @@: ;-----------------------GET STARTING CLUSTER OF SUBDIR
- GetStartClust: mov al,CurrDir
- or al,al ;root?
- jz @F ;yes,nevermind
-
- mov cx,10h ;look for "."
- mov dx,OFFSET ThisDir
- mov ah,4Eh ;find first file
- int 21h
-
- push es
- mov es,PSPseg
- mov ax,es:[81h] ;get first two characters of template
- cmp ax,' .' ;should be dot-space, inteled
- mov ax,es:[8Fh] ;cluster number
- pop es
- jne GetStartClust01 ;was not dot-space
- mov StartCluster,ax
- jmp SHORT @F
-
- GetStartClust01:mov bl,EInvalidDTANo
- jmp Bail
-
- @@: ;-----------------------VECTOR INT1B TO LOCAL HANDLER
- INT1Btrap: mov bl,1
- call INT1Bswitch ;this must be restored before exiting
-
- @@: ;-----------------------VECTOR INT00 TO LOCAL HANDLER
- INT00trap: mov bl,1
- call INT00switch ;this must be restored before exiting
-
- @@: ;-----------------------GET DEVICE PARMS
- GetDeviceParms: mov bl,CurrDrive
- sub bh,bh
- mov cx,0860h
- mov BuffDeviceParms.dpSpecFunc,1 ;get curr medium info
- mov dx,OFFSET BuffDeviceParms
- mov ax,440Dh
- int 21h
- jnc @F
- mov bl,EAccessNo
- jmp Bail
-
- @@: ;-----------------------IS DEVICE KNOWN
- ChkDevice: mov al,BuffDeviceParms.dpDevType
- mov di,OFFSET ValidDevices
- mov cx,ValidDevicesL
- repne scasb
- je @F ;can handle device
- mov bl,EUnkDeviceNo
- jmp Bail
- @@: cmp WPTR BuffDeviceParms.dpHiddenSecs+2,0
- je @F
- mov bl,ERootFarNo ;root dir not in first 64K DOS sectors
- jmp Bail
-
- @@: ;-----------------------CALC FAT/ROOT/DATA SECTOR START
- GetBase: mov ax,BuffDeviceParms.dpResSectors
- add ax,WPTR BuffDeviceParms.dpHiddenSecs
- jc GetBase01
- mov bx,ax
- mov FATsector,ax
- mov al,BuffDeviceParms.dpFATs
- sub ah,ah
- mul BuffDeviceParms.dpFATsecs
- jc GetBase01
- add ax,bx
- jc GetBase01
- mov ROOTsector,ax
- mov ax,BuffDeviceParms.dpRootDirEnts
- mov cx,32
- mul cx
- div BuffDeviceParms.dpBytesSector
- mov dx,ROOTsector
- add ax,dx
- mov DATAsector,ax
- mov ax,BuffDeviceParms.dpBytesSector
- mov dl,BuffDeviceParms.dpSectorsClust
- sub dh,dh
- mul dx
- jc GetBase01
- mov BytesCluster,ax
- jmp SHORT @F
-
- GetBase01: mov bl,ERootFarNo ;root dir not in first 64K DOS sectors
- jmp Bail
-
- @@: ;-----------------------CLEAR DIR SORT BUFFER
- ClearSortBuff: sub ax,ax
- mov cx,SIZE BuffDirSort/2
- mov di,OFFSET BuffDirSort
- rep stosw
-
- @@: ;-----------------------DETERMINE SORT TYPE
- SortWhatDir: call ShowDrvInfo
- call ShowDirInfo
- call OutputCRLF
- mov al,CurrDir
- or al,al ;root?
- jz @F ;yes
- jmp SHORT SortSubDir
-
- @@: ;-----------------------SORT ROOT DIRECTORY
- SortRootDir: mov ax,BuffDeviceParms.dpRootDirEnts
- mov cx,32
- mul cx
- div BuffDeviceParms.dpBytesSector
- mov cx,ax ;cx=root dir sectors
- mov ax,ROOTsector
- sub dx,dx ;dx:ax=first DOS sector
- mov di,OFFSET BuffDirSort+32 ;es:di->buffer
- call ReadDOSsectors
- call CountUsedEnts ;cx=entries to sort,dx=last HSD entry
- mov bp,di ;di=deleted entries (still sorted)
-
- push cx ;save entries to sort
- push dx ;save entries skipped
-
- push cx ;and entries to sort again
- mov di,OFFSET SortInfo
- mov ax,dx
- sub dx,dx
- call Hex2ASCII
- dec di ;backup over Z
- mov al,'/' ;es:di->next slot in output buffer
- stosb
- pop ax ;get entries to sort
- sub ax,bp ;deleted entries not counted in list
- sub dx,dx
- call Hex2ASCII
-
- pop dx ;get 'em back
- pop cx
- cmp cx,1 ;0 or 1 entries?
- jbe @F ;yes
- inc dx ;dx=first entry to start sort at
- add cx,dx ;A1*last item position+1
- dec cx ;A1*last item position
- call QuiksortFN
-
- sub ax,ax
- sub dx,dx ;use same parms as read
- call WriteDOSsectors
-
- @@: call ShowSortInfo
- call OutputCRLF
- sub bl,bl ;done okay
- jmp Bail
-
- @@: ;-----------------------SORT SUBDIRECTORY
- SortSubDir:
- @@: ;-----------------------ALLOCATE, LOAD (& COMPARE) FAT(S) BUFFER
- AllocReadFAT: mov ax,BuffDeviceParms.dpFATsecs
- mul BuffDeviceParms.dpBytesSector
- jc AllocReadFAT01 ;FAT > 64K-1
- mov bp,ax ;save bytes needed for FAT buffer
- mov cl,4
- shr ax,cl ;get paras needed for FAT
- mov bx,ax
- mov ah,48h
- int 21h
- jc AllocReadFAT01 ;not enough memory
- mov SegBuffFAT,ax ;segment of FAT buffer
-
- cmp BuffDeviceParms.dpFATs,1
- je @F ;only 1 FAT
-
- mov ah,48h ;get buffer for FAT2
- int 21h
- jc AllocReadFAT01 ;not enough memory
- mov SegBuffFAT2,ax ;segment of FAT2 buffer
-
- sub di,di ;load FAT2
- mov es,ax ;es:di->FAT2 buffer
- mov ax,FATsector
- add ax,BuffDeviceParms.dpFATsecs
- sub dx,dx ;dx:ax=first FAT2 sector
- mov cx,BuffDeviceParms.dpFATsecs ;sectors to read
- call ReadDOSsectors
-
- @@: sub di,di ;load FAT
- mov es,SegBuffFAT ;es:di->FAT buffer
- mov ax,FATsector
- sub dx,dx ;dx:ax=first FAT sector
- mov cx,BuffDeviceParms.dpFATsecs ;sectors to read
- call ReadDOSsectors
-
- cmp BuffDeviceParms.dpFATs,1
- je @F ;can't compare if only 1 FAT
-
- mov dx,ds ;save ds in dx for a sec
- sub si,si
- sub di,di
- mov es,SegBuffFAT2
- mov ds,SegBuffFAT
- mov cx,bp
- shr cx,1 ;compare words
- repe cmpsw
- jne AllocReadFAT02 ;FATs do not match
-
- mov ah,49h ;deallocate FAT 2 buffer
- int 21h
- mov ds,dx ;restore seg regs
- mov es,dx
- jmp SHORT @F
-
- AllocReadFAT01: mov bl,ENoFATmemoryNo
- jmp Bail
-
- AllocReadFAT02: mov ds,dx ;restore seg regs
- mov es,dx
- mov bl,EFATnoMatchNo
- jmp Bail
-
- @@: ;-----------------------GET ALL CLUSTERS ASSIGNED TO THIS SUBDIR
- FATtruckin: mov FATtype,16
- mov ax,BuffDeviceParms.dpSectors
- or ax,ax ;huge part?
- jz @F ;yes
- sub dx,dx
- sub bh,bh
- mov bl,BuffDeviceParms.dpSectorsClust
- div bx ;ax=clusters on drive
- cmp ax,4087 ;4087+ uses 16-bit FAT
- jae @F
- mov FATtype,12 ;else a 12-bit FAT
-
- @@: mov cx,32 ;B2*determine how many clusters the
- mov ax,MAXDIR ;directory entry buffer is
- mul cx ;ax=MAXDIR*32=bytes available
- div BytesCluster ;ax=clusters available
- mov cx,ax ;count actual clusters available
- jcxz @F ;B2* buff not large enough for 1 cluster
-
- push ds
- mov ds,SegBuffFAT ;ds:si->FAT (si set in FollowFAT1x)
- mov di,OFFSET ClusterList
- mov ax,es:StartCluster ;es:di->ClusterList array
- FATtruckin01: stosw ;put links--
- cmp es:FATtype,12 ;doing a 12-bit FAT?
- jne FATtruckin02 ;no
- call FollowFAT12 ;yes
- jmp SHORT FATtruckin03
- FATtruckin02: call FollowFAT16 ;16-bit FAT
- FATtruckin03: or ax,ax ;0 then at end of link
- jz FATtruckin04
- loop FATtruckin01
- pop ds ;ds=DGROUP
- @@: mov bl,EFATlinkNo ;too many clusters for buffer
- jmp Bail
- FATtruckin04: stosw ;0 demarks end of ClusterList
- pop ds ;ds=DGROUP
-
- @@: ;-----------------------READ SUBDIR CLUSTERS
- ReadSubDirClust:mov si,OFFSET ClusterList ;ds:si->ClusterList array
- mov bl,BuffDeviceParms.dpSectorsClust
- sub bh,bh ;bx=sectors/cluster (sectors to read)
- mov cx,bx ;cx=sectors to read
- mov di,OFFSET BuffDirSort+32 ;es:di=>dir sort buffer
-
- @@: lodsw ;get a cluster from list
- or ax,ax ;done?
- jz SortSD01 ;yes
- dec ax ;no,convert cluster to DOS LOGSEC
- dec ax ;subtract 2...
- mul bx ;times sectors/cluster=DOS data sector
- add ax,DATAsector ;add in relative data start sector
- adc dx,0 ;dx:ax=32-bit sector number
- push bx ;save multiplier
- push cx ;save sector read count
- push di ;save buffer address
- call ReadDOSsectors ;read cluster's sectors to buffer
- pop di
- pop cx
- pop bx
- add di,BytesCluster
- jmp @B
-
- @@: ;-----------------------SORT SUBDIR BUFFER
- SortSD01: mov di,OFFSET BuffDirSort+32 ;es:di->buffer
- call CountUsedEnts ;cx=entries to sort,dx=last HSD entry
- mov bp,di ;di=deleted entries (still sorted)
-
- push cx ;save entries to sort
- push dx ;save entries skipped
-
- push cx ;and entries to sort again
- mov di,OFFSET SortInfo
- mov ax,dx
- sub dx,dx
- call Hex2ASCII
- dec di ;backup over Z
- mov al,'/' ;es:di->next slot in output buffer
- stosb
- pop ax ;get entries to sort
- sub ax,bp ;deleted entries not counted in list
- sub dx,dx
- call Hex2ASCII
-
- pop dx ;get 'em back
- pop cx
- cmp cx,1 ;0 or 1 entries?
- jbe SkipSort ;yes
- inc dx ;dx=first entry to start sort at
- add cx,dx ;A1*last item position+1
- dec cx ;A1*last item position
- call QuiksortFN
-
- @@: ;-----------------------WRITE SUBDIR CLUSTERS
- WriteSubDirClust:mov si,OFFSET ClusterList ;ds:si->ClusterList array
- mov bl,BuffDeviceParms.dpSectorsClust
- sub bh,bh ;bx=sectors/cluster (sectors to read)
- mov cx,bx ;cx=sectors to read
- mov di,OFFSET BuffDirSort+32 ;es:di=>dir sort buffer
-
- @@: lodsw ;get a cluster from list
- or ax,ax ;done?
- jz @F ;yes
- dec ax ;no,convert cluster to DOS LOGSEC
- dec ax ;subtract 2...
- mul bx ;times sectors/cluster=DOS data sector
- add ax,DATAsector ;add in relative data start sector
- adc dx,0 ;dx:ax=32-bit sector number
- push bx ;save multiplier
- push cx ;save sector read count
- push di ;save buffer address
- call WriteDOSsectors ;write cluster's sectors to buffer
- pop di
- pop cx
- pop bx
- add di,BytesCluster
- jmp @B
- @@:
- SkipSort: call ShowSortInfo
- call OutputCRLF
-
- @@: ;-----------------------DONE
- AllDone: mov ah,0Dh ;drive reset
- int 21h
-
- sub bl,bl
- jmp Bail
-
- ;=======================
- ;SUBROUTINES
-
- ;-----------------------FOLLOW FAT12 CHAIN
- ;USES: ax,bx,dx,si RET: ax=next cluster,=0 if last link
- FollowFAT12: test ax,1 ;FAT entry number odd?
- pushf ;save for a sec
- mov bx,3 ;determine if last link
- mul bx ;dx:ax=Link * 3
- shr dx,1
- rcr ax,1 ;dx:ax=Link * 1.5
- mov si,ax
- mov ax,[si] ;get next cluster
- popf
- jnz @F ;yes odd
- and ax,0FFFh ;even link use right 12 bits
- jmp SHORT FollowFAT1201
- @@: shr ax,1 ;odd link use left 12 bits
- shr ax,1
- shr ax,1
- shr ax,1
- FollowFAT1201: cmp ax,0FF8h ;end link?
- jb @F ;no
- sub ax,ax ;yes,return 0
- @@: retn ;return cluster number
-
- ;-----------------------FOLLOW FAT16 CHAIN
- ;USES: ax,si RET: ax=next cluster,=0 if last in link
- FollowFAT16: shl ax,1 ;ax=ax*2
- mov si,ax
- mov ax,[si] ;get link word
- cmp ax,0FFF8h ;end link?
- jb @F ;no
- sub ax,ax ;yes,return 0
- @@: retn ;return cluster number
-
- ;-----------------------CONV DOS LOGICAL SECTOR TO CYL/HD/SEC
- ;USES: ax,cx,dx RET: DOScylinder,DOShead,DOSsector
- ConvLOGSEC: mov ax,BuffDeviceParms.dpSectorsTrack
- mul BuffDeviceParms.dpHeads
- mov cx,ax ;cx=CylSec,sectors on cylinder
- mov ax,WPTR LogSec
- mov dx,WPTR LogSec+2 ;dx:ax=32-bit DOS sector
- div cx ;ax=cyl,cylinder of DOS sector
- mov DOScylinder,ax
- mul cx ;dx:ax=cyl*CylSec
- sub ax,WPTR LogSec
- sbb dx,WPTR LogSec+2
- not dx ;negate
- neg ax
- sbb dx,-1 ;dx:ax=32-bit sector offset (dx=0)
- mov cx,ax ;cx=rm,sectors into this DOS cylinder
- div BuffDeviceParms.dpSectorsTrack
- mov DOShead,ax
- mul BuffDeviceParms.dpSectorsTrack
- sub cx,ax
- mov DOSsector,cx
- retn
-
- ;-----------------------ZERO BuffDirSort
- ;USES: ax,cx,di
- ZeroBuffDirSort:sub ax,ax
- mov cx,(MAXDIR+1)*32/2
- mov di,OFFSET BuffDirSort
- rep stosw
- retn
-
- ;-----------------------COUNT DIRECTORY ENTRIES TO SORT
- ;USES: ax,bx,si,di RET: cx,dx,di FIND LAST H/S/D ENTRY & DEL#
- CountUsedEnts: mov si,OFFSET BuffDirSort+32
- sub cx,cx ;track entries to sort
- mov dx,cx ;track last HSD entry
- mov di,cx ;track deleted entries
- mov bx,31
- @@: lodsb ;first byte of filename (0=unused entry)
- or al,al ;B4* unused?
- jz CountUsedEnts3 ;B4*
- inc cx ;B4* used entry count
- mov ah,[si+10] ;attribute (si incremented by lodsb)
- test ah,16h ;system,hidden,subdir entry?
- jz CountUsedEnts1 ;no
- cmp al,0E5h ;erased system,hidden,subdir entry?
- je CountUsedEnts1 ;yes
- mov dx,cx ;current max hidden/system entry
- sub di,di ;zero deleted entries not skipped
- CountUsedEnts1: cmp al,0E5h ;track number of deleted entries
- jne CountUsedEnts2
- inc di
- CountUsedEnts2: add si,bx
- jmp @B
- CountUsedEnts3: sub cx,dx ;cx=directory entries to sort
- retn ;dx=last hidden/system/subdir entry or 0
- ;di=deleted entries not skipped
-
- ;-----------------------OUTPUT CR/LF
- ;USES: ah,bx,cx,dx
- OutputCRLF: mov dx,OFFSET CRLF
- mov cx,2
- mov bx,STDOUT
- mov ah,40h
- int 21h
- retn
-
- ;-----------------------SHOW DRIVE BEING SORTED
- ;USES: ax,bx,cx,dx
- ShowDrvInfo: mov al,CurrDrive
- add al,'@'
- mov CurrDrvMsg,al
- mov dx,OFFSET CurrDrvMsgPre
- mov cx,CurrDrvMsgPreL
- mov bx,STDOUT
- mov ah,40h
- int 21h
- retn
-
- ;-----------------------SHOW DIRECTORY BEING SORTED
- ;USES: ax,bx,cx,dx,di
- ShowDirInfo: mov cx,40h ;max dir length
- mov di,OFFSET CurrDir
- sub al,al
- repne scasb
- sub cx,40h
- neg cx
- dec cx
- jcxz @F
- mov dx,OFFSET CurrDir
- mov bx,STDOUT
- mov ah,40h
- int 21h
- @@: retn
-
- ;-----------------------SHOW SORT INFO
- ;USES: ah,bx,cx,dx
- ShowSortInfo: mov dx,OFFSET MSortInfo
- mov cx,MSortInfoL
- mov bx,STDOUT
- mov ah,40h
- int 21h
- @@: retn
-
- ;-----------------------READ TRACK ON LOGICAL DRIVE
- ;USES: ax,bx,cx,dx RET: NC=okay CY=error in ax
- ReadTrack: mov bl,CurrDrive
- sub bh,bh
- mov cx,0861h ;device category/read track
- mov dx,OFFSET rBlock ;read block structure
- mov ax,440Dh
- int 21h
- retn ;carry set on error/ax=1,2,5
-
- ;-----------------------WRITE TRACK ON LOGICAL DRIVE
- ;USES: ax,bx,cx,dx RET: NC=okay CY=error in ax
- WriteTrack: mov bl,CurrDrive
- sub bh,bh
- mov cx,0841h ;device category/write track
- mov dx,OFFSET wBlock ;write block structure
- mov ax,440Dh
- int 21h
- retn ;carry set on error/ax=1,2,5
-
- ;-----------------------READ CX DOS SECTORS AT DX:AX TO ES:DI
- ;USES: ax,cx,dx (CONSECUTIVE PHYSICAL SECTORS)
- ReadDOSsectors: mov WPTR LOGSEC,ax
- mov WPTR LOGSEC+2,dx
- sub ax,ax
- mov rBlock.rwSpecFunc,al
- mov wBlock.rwSpecFunc,al ;load write block too
- push cx
- call ConvLOGSEC
- pop cx
- mov ax,DOShead
- mov rBlock.rwHead,ax
- mov wBlock.rwHead,ax
- mov ax,DOScylinder
- mov rBlock.rwCylinder,ax
- mov wBlock.rwCylinder,ax
- mov ax,DOSsector
- mov rBlock.rwFirstSector,ax
- mov wBlock.rwFirstSector,ax
- mov rBlock.rwSectors,cx
- mov wBlock.rwSectors,cx
- mov WPTR rBlock.rwBuffer,di
- mov WPTR rBlock.rwBuffer+2,es
- mov WPTR wBlock.rwBuffer,di
- mov WPTR wBlock.rwBuffer+2,es
- call ReadTrack
- jnc @F
- mov bl,EAccessNo
- jmp Bail
- @@: retn
-
- ;-----------------------WRITE CX DOS SECTORS AT DX:AX FROM ES:DI
- ;USES: ax,cx,dx (CONSECUTIVE PHYSICAL SECTORS)
- WriteDOSsectors:or ax,ax ;use same info as last read?
- jnz @F ;no
- or dx,dx
- jz WriteSame ;yes, use last read's parms
- @@: mov WPTR LOGSEC,ax
- mov WPTR LOGSEC+2,dx
- sub ax,ax
- mov wBlock.rwSpecFunc,al
- push cx
- call ConvLOGSEC
- pop cx
- mov ax,DOShead
- mov wBlock.rwHead,ax
- mov ax,DOScylinder
- mov wBlock.rwCylinder,ax
- mov ax,DOSsector
- mov wBlock.rwFirstSector,ax
- mov wBlock.rwSectors,cx
- mov WPTR wBlock.rwBuffer,di
- mov WPTR wBlock.rwBuffer+2,es
- WriteSame: call WriteTrack
- jnc @F
- mov bl,EAccessNo
- jmp Bail
- @@: retn
-
- ;-----------------------OUTPUT DX:AX IN ASCII TO ES:DI
- ;USES: ax,bx,cx,dx,si,di RET: di->next slot,ASCII output @ ES:DI
- Hex2ASCII: mov si,10 ;base
- mov bx,ax
- mov cx,dx
- mov dx,-1 ;conv digits stored on stack after -1
- push dx
- Hex2ASCII01: xchg ax,cx ;ax=high word
- sub dx,dx
- div si
- xchg cx,ax ;cx=high divide
- xchg ax,bx ;ax=low word,dx=remainder
- div si
- xchg bx,ax ;bx=low divide
-
- add dl,'0' ;make ASCII
- push dx ;save 'em
- or bx,bx ;more left to divide?
- jne Hex2ASCII01 ;yes
- or cx,cx
- jne Hex2ASCII01 ;yes
-
- mov bl,'0' ;in case dx:ax=0 and leading zero flag
- Hex2ASCII02: pop dx ;get 'em
- cmp dx,-1 ;all done?
- je Hex2ASCII04 ;yes
- or bl,dl ;set bl to indicate leading '0' or not
- cmp bl,'0' ;still a leading zero?
- je @F ;yes,skip it
- mov al,dl
- stosb
- @@: jmp SHORT Hex2ASCII02
-
- Hex2ASCII04: cmp bl,'0' ;dx:ax=0?
- jne @F ;no
- mov al,bl
- stosb
- @@: sub al,al ;zero terminate it
- stosb
- retn
-
- COMMENT ~ Not needed, see above
- ;-----------------------TRAP INT24
- ;USES: none
- INT24switch: push es
- push ds
- push dx
- push ax
-
- mov Trap24,bl
- or bl,bl ;trap or restore?
- jz INT24s2 ;0=restore
-
- mov INT24error,0
- mov ax,3524h
- int 21h
- mov INT24seg,es
- mov INT24off,bx
- mov ax,2524h
- mov dx,OFFSET INT24handler
- push cs
- pop ds
- INT24s1: int 21h
- pop ax
- pop dx
- pop ds
- pop es
- retn
-
- INT24s2: mov ax,2524h
- mov dx,INT24off
- mov ds,INT24seg
- jmp INT24s1
-
- INT24handler: sti ;INT24 HANDLER
- add sp,6
- mov ax,di
- sub ah,ah
- add ax,13h
- mov ss:INT24error,ax
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- pop di
- pop bp
- pop ds
- pop es
- iret
- END COMMENT ~
-
- ;-----------------------TRAP INT23
- ;USES: none
- INT23switch: push es
- push ds
- push dx
- push ax
-
- mov Trap23,bl
- or bl,bl ;trap or restore?
- jz INT23s2 ;0=restore
-
- mov ax,3523h
- int 21h
- mov INT23seg,es
- mov INT23off,bx
- mov ax,2523h
- mov dx,OFFSET INT23handler
- push cs
- pop ds
- INT23s1: int 21h
- pop ax
- pop dx
- pop ds
- pop es
- retn
-
- INT23s2: mov ax,2523h
- mov dx,INT23off
- mov ds,INT23seg
- jmp INT23s1
-
- INT23handler: iret ;INT23 HANDLER
-
- ;-----------------------TRAP INT1B
- ;USES: none
- INT1Bswitch: push es
- push ds
- push dx
- push ax
-
- mov Trap1B,bl
- or bl,bl ;trap or restore?
- jz INT1Bs2 ;0=restore
-
- mov ax,351Bh
- int 21h
- mov INT1Bseg,es
- mov INT1Boff,bx
- mov ax,251Bh
- mov dx,OFFSET INT1Bhandler
- push cs
- pop ds
- INT1Bs1: int 21h
- pop ax
- pop dx
- pop ds
- pop es
- retn
-
- INT1Bs2: mov ax,251Bh
- mov dx,INT1Boff
- mov ds,INT1Bseg
- jmp INT1Bs1
-
- INT1Bhandler: push ax ;INT1B HANDLER
- mov al,20h
- out 20h,al
- pop ax
- iret
-
- ;-----------------------TRAP INT00
- ;USES: none
- INT00switch: push es
- push ds
- push dx
- push ax
-
- mov Trap00,bl
- or bl,bl ;trap or restore?
- jz INT00s2 ;0=restore
-
- mov ax,3500h
- int 21h
- mov INT00seg,es
- mov INT00off,bx
- mov ax,2500h
- mov dx,OFFSET INT00handler
- push cs
- pop ds
- INT00s1: int 21h
- pop ax
- pop dx
- pop ds
- pop es
- retn
-
- INT00s2: mov ax,2500h
- mov dx,INT00off
- mov ds,INT00seg
- jmp INT00s1
-
- INT00handler: add sp,6 ;remove iret junk
- mov bl,EMathNo ;INT00 HANDLER
- jmp Bail
-
- ;-----------------------SORT DIRSORT BUFFER BY FILENAME/EXT
- ;Use your own sort routine
- ;if SortMode='@' or 'N' sort by filename, if 'E' then extension
- ;dir entries start at BuffDirSort+32
- ;with cx=last entry to sort dx=entry to start sort at
- QuiksortFN: mov bl,EInvalidFuncNo
- jmp Bail
-
- END Start
-
-
-
-