home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pcmag
/
vol6n02.arc
/
DIRCOMP.ASM
next >
Wrap
Assembly Source File
|
1987-12-13
|
13KB
|
427 lines
; DIRCOMP.ASM -- Lists two directories side by side
; =================================================
CSEG Segment
Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
Org 0080h
Parameter Label Byte ; Parameter is here
Org 0100h
Entry: Jmp Begin ; Entry Point
; Most Data (some more at end of program)
; ---------------------------------------
db "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
db " Programmed by Charles Petzold ",1Ah
SyntaxMsg db "Syntax: DIRCOMP filespec filespec$"
DosVersMsg db "DIRCOMP: Needs DOS 2.0 +$"
FileSpecMsg db "DIRCOMP: Bad file name$"
TooManyMsg db "DIRCOMP: Too many files$"
MemAllocMsg db "DIRCOMP: Not enough memory$"
Delimiters db 9,' ,;='
FileList1 dd 0, ? ; Storage of found files
FileList2 dd 0, ?
FileCount1 dw 0 ; Count of found files
FileCount2 dw 0
Append db '\*.*', 0
; Check DOS Version
; -----------------
Begin: Mov AH, 30h ; Check for DOS Version
Int 21h ; through DOS call
Cmp AL, 2 ; See if it's 2.0 or above
Jae DosVersOK ; If so, continue
Mov DX, Offset DosVersMsg ; Error message
ErrorExit: Mov AH, 9 ; Print String function call
Int 21h ; Do it
Int 20h ; And exit prematurely
; Parse Command Line to get file specifications
; ---------------------------------------------
DosVersOK: Cld ; Directions forward
Mov SI, Offset Parameter ; Parameter string
Lodsb ; Length of Parameter
Mov BL, AL ; Make BX the length
Sub BH, BH
Mov Word Ptr [SI + BX], 0D20h ; Put blank at end
Mov DI, Offset FileSpec1 ; Destination of first spec
Call GetFileSpec ; Transfer it and fix it up
Mov DI, Offset FileSpec2 ; Destination of second spec
Call GetFileSpec ; Transfer it and fix it up
; De-Allocate rest of memory
; --------------------------
Mov DX, Offset MemAllocMsg ; Possible error message
Mov SP, Offset StackTop ; Bring in stack pointer
Mov BX, SP ; Also end of needed memory
Add BX, 15 ; Add 15 for truncation
Mov CL, 4 ; Shift 4 bits right
Shr BX, CL
Mov AH, 4Ah ; Change memory size
Int 21h ; through DOS
Jc ErrorExit ; If problem, terminate
; Find Files from file specification
; ----------------------------------
Mov DX, Offset DTABuffer ; Set File Find buffer
Mov AH, 1Ah ; by calling DOS
Int 21h
Mov DX, Offset FileSpec1 ; First file specification
Call GetFilesAndSort ; Do as it says
Mov Word Ptr [FileList1 + 2], AX ; Segment of file list
Mov [FileCount1], CX ; Number of files
Mov DX, Offset FileSpec2 ; Second file specification
Call GetFilesAndSort ; Do it again
Mov Word Ptr [FileList2 + 2], AX ; Segment of file list
Mov [FileCount2], CX ; Number of files
; Now Display List on Screen
; --------------------------
DoAnother: Lea DI, DisplayString ; Destination of display line
Mov AL, ' '
Cmp [FileCount1],0 ; See if any more left
Jz FirstColDone ; If so, first column is blank
Cmp [FileCount2],0 ; See if second is done
Jz ListOnly1 ; If so, 2nd column is blank
Push SI
Push DI
Push DS
Push ES
Les DI, [FileList2] ; Address of second list
Lds SI, [FileList1] ; Address of first list
Mov CX, 12 ; Number of bytes to compare
Repz Cmpsb ; Compare them
Pop ES ; Get back registers
Pop DS
Pop DI
Pop SI
Jb ListOnly1 ; If file 1 < file 2, list 1
Ja ListOnly2 ; If file 1 > file 2, list 2
Call ListFile1 ; Put first in display string
Stosb ; Put a blank after it
Jmp Short DoSecond ; Now do second file
FirstColDone: Cmp [FileCount2], 0 ; See if second done also
Jz AllDone ; If so, we're done
ListOnly2: Mov CX, 40 ; If not, store 40 blanks
Rep Stosb
DoSecond: Call ListFile2 ; Put 2nd file in display str
Jmp Short WriteCRLF ; And append a CR/Lf
ListOnly1: Call ListFile1 ; Put 1st file in display str
Mov CX, 40 ; Blank out second half
Rep Stosb
WriteCRLF: Mov AX, 0A0Dh ; Put CR/LF at end of string
Stosw
SpillOut: Lea DX, DisplayString ; Address of display string
Mov CX, 81 ; Number of characters
Mov BX, 1 ; Standard output
Mov AH, 40h ; Write to screen
Int 21h ; through DOS
Jmp DoAnother ; And do the next one
AllDone: Int 20h ; All done -- terminate
; SUBROUTINE: Get File Spec (uses DI to point to destination)
; -----------------------------------------------------------
GetFileSpec: Mov DX, DI ; Save pointer in DX
Search: Call ScanParam ; Check next byte
Je Search ; If delimiter, keep searching
SearchEnd: Stosb ; Save the character
Call ScanParam ; Check the next byte
Jne SearchEnd ; If not delimiter, continue
Mov Byte Ptr [DI], 0 ; Make it an ASCIIZ string
Push SI ; Save parameter pointer
Mov SI, 1 + Offset Append ; Set to *.* string
Mov CX, 4 ; Possible 4 bytes to move
Cmp Byte Ptr [DI - 1], ':' ; Do it if last character is :
Jz AppendStuff
Cmp Byte Ptr [DI - 1], '\' ; Or if last character is \
Jz AppendStuff
Mov AX, 4300h ; Get file attribute
Int 21h ; through DOS
Jc FixUpDone ; If error, do no more
Test CL, 10h ; See if it's directory
Jz FixUpDone ; If not, do no more
Dec SI ; If so, append \*.*
Inc CX ; which has five characters
AppendStuff: Rep Movsb ; Append string to file spec
FixUpDone: Pop SI ; And done with this stuff
Ret
; SUBROUTINE: Scan Parameter
; --------------------------
ScanParam: Push DI ; Save destination pointer
Lodsb ; Get byte from parameter
Cmp AL, 13 ; See if end of parameter
Jne NotAtEnd ; If so, got an error
Mov DX, Offset SyntaxMsg ; Load up error message
Jmp ErrorExit ; and exit
NotAtEnd: Mov DI, Offset Delimiters ; Check if delimiter
Mov CX, 5 ; There are 5 of them
Repne Scasb ; Scan the string
Pop DI ; Get back pointer
Ret ; And return
; SUBROUTINE: Get Files and Sort
; ------------------------------
GetFilesAndSort:Push ES
Mov BX, 1000h ; Try to allocate 64K memory
Mov AH, 48h ; through DOS
Int 21h
Jnc AllocateOK ; If no error, we've got it
Mov AH, 48h ; Otherwise allocate
Int 21h ; as much as possible
AllocateOK: Mov CL, 4 ; Turn BX into an offset
Shl BX, CL
Sub BX, 20 ; Take away 20 bytes
Mov ES, AX ; Set ES to memory segment
Sub DI, DI ; Point to beginning
Sub BP, BP ; File Counter
Mov CX, 06h ; Normal, hidden, system files
Mov AH, 4Eh ; Find first file
FindFile: Int 21h ; Call DOS to find file
Jnc Continue ; If no error continue
Cmp AX, 18 ; If no more files
Jz NoMoreFiles ; get out of the loop
Mov DX, Offset FileSpecMsg ; Error message otherwise
Jmp ErrorExit ; Exit and print message
Continue: Cmp DI, BX ; See if end of segment
Jb StillOK ; If not, continue
TooManyFiles: Mov DX, Offset TooManyMsg ; Otherwise error message
Jmp ErrorExit ; And terminate
StillOK: Inc BP ; Kick up file counter
Mov SI, 30+Offset DTABuffer ; Points to filename
Mov CX, 12 ; 12 bytes to transfer
TransName: Lodsb ; Get a byte
Or AL, AL ; See if it's zero
Jz NameDone ; If so, transfer done
Cmp AL, '.' ; See if it's period
Jnz NotPeriod ; If not keep going
Sub CX, 3 ; If period, adjust counter
Mov AL, ' ' ; Pad names with blanks
Rep Stosb
Add CX, 3 ; Re-adjust counter
Jmp TransName ; And continue
NotPeriod: Stosb ; If not period, just store it
Loop TransName ; And keep going
NameDone: Mov AL, ' ' ; Pad end of name with blanks
Rep Stosb
Mov SI, 22+Offset DTABuffer ; Point to time/date/size
Mov CX, 4 ; Save that stuff too
Rep Movsw
Mov AH, 4Fh ; Find next file
Jmp FindFile
NoMoreFiles: Mov BX, DI ; End of file storage
Add BX, 15 ; Convert to paragraph
Mov CL, 4
Shr BX, CL
Mov AH, 4Ah ; Re-adjust memory
Int 21h
; Sort Files
; ----------
Push DS ; Save DS
Push ES
Pop DS ; Point DS to files
Sub DI, DI ; This is the beginning
Mov CX, BP ; Number of files to sort
Jcxz AllSorted ; If no files, we're done
Dec CX ; Loop needs one less than CX
Jcxz AllSorted ; But zero means only one file
SortLoop1: Push CX ; Save the file counter
Mov SI, DI ; Set source to destination
SortLoop2: Add SI, 20 ; Set source to next file
Push CX ; Save the counter,
Push SI ; compare source,
Push DI ; and compare destination
Mov CX, 20 ; 20 characters to compare
Repz Cmpsb ; Do the compare
Jae NoSwitch ; Jump if already in order
Pop DI ; Get back these registers
Pop SI
Push SI ; And push them again for move
Push DI
Mov CX, 20 ; 20 characters
SwitchLoop: Mov AL, ES:[DI] ; Character from destination
Movsb ; Source to destination
Mov DS:[SI - 1], AL ; Character to source
Loop SwitchLoop ; For the rest of the line
NoSwitch: Pop DI ; Get back the registers
Pop SI
Pop CX
Loop SortLoop2 ; And loop for next file
Pop CX ; Get back file counter
Add DI, 20 ; Compare with next file
Loop SortLoop1 ; And loop again
AllSorted: Pop DS ; Get back to normal
Mov AX, ES ; File segment in AX
Pop ES
Mov CX, BP ; File count in CX
Ret
; SUBROUTINES for listing files on screen
; ---------------------------------------
ListFile1: Push DS
Lds SI, [FileList1] ; Set to address of list
Call ListFile ; Put it into DisplayString
Pop DS
Mov Word Ptr [FileList1], SI ; Save new pointer
Dec [FileCount1] ; Decrement count
Ret
ListFile2: Push DS
Lds SI, [FileList2] ; Set to address of list
Call ListFile ; Put it into DisplayString
Pop DS
Mov Word Ptr [FileList2], SI ; Save new pointer
Dec [FileCount2] ; Decrement count
Ret
ListFile: Push AX
Push SI
Push DI
Mov CX, 12 ; 12 characters in file name
Rep Movsb ; Transfer them
Mov AL, ' ' ; Blank out the rest
Mov CX, 27
Rep Stosb
Sub DI, 6 ; Point to time destination
Lodsw ; Get the coded time
Mov BL, 01Fh ; AND mask for hours
Mov BH, '0' ; Zero-blank indicator
Mov CL, 11 ; Shift value for hours
Sub DL, DL ; Offset for hours
Mov DH, ':' ; Following character
Call DateTime ; Do the transfer routine
Mov BX, 3Fh ; Zero OK / AND Mask for minutes
Mov CL, 5 ; Shift value of minutes
Mov DH, ' ' ; Following character
Call DateTime ; Do the transfer routine
Sub DI, 16 ; Point to date destination
Lodsw ; Get the coded date
Mov BL, 0Fh ; AND mask for month
Mov BH, '0' ; Zero-blank indicator
Mov CL, 5 ; Shift value for month
Mov DH, '-' ; Following character
Call DateTime ; Do the transfer routine
Mov BX, 1Fh ; Zero OK / AND mask for day
Mov CL, 0 ; Shift value for day
Call DateTime ; Do the transfer routine
Mov BL, 7Fh ; AND mask for year
Mov CL, 9 ; Shift value for year
Mov DL, 80 ; Offset for year
Mov DH, ' ' ; Following character
Call DateTime ; Do the transfer routine
Sub DI, 12 ; Point to end of file size space
Lodsw ; Get low word
Mov DX, AX ; Save it in DX
Lodsw ; AX is high word, DX low word
Mov BX, 10 ; Will divide by 10 for ASCII
Std ; Direction backward
AsciiLoop: Mov CX, DX ; Save low word in CX
Sub DX, DX ; Zero out DX for division
Div BX ; AX = quotient, DX = remainder
Xchg AX, CX ; Now AX = low word, CX = quotient1
Div BX ; AX = quotient2, DX = remainder
Xchg AX, DX ; AX = remainder, DX = quotient2
Add AL, '0' ; Adjust for ASCII
Stosb ; Store it
Mov AX, CX ; See if zero is left
Or CX, DX
Jnz AsciiLoop ; If not, continue
Cld ; Get back to normal
Pop DI
Pop SI
Pop AX
Add SI, 20 ; Next file in list
Add DI, 39 ; Next byte in destination
Ret
; SUBROUTINE: Date and Time Display
; ---------------------------------
DateTime: Push AX
Push BX
Push CX
Push DX
Shr AX, CL ; Shift word left by CL bits
And AL, BL ; AND it with BL mask
Add AL, DL ; Offset it by DL
Sub AH, AH ; Zero out high byte
Mov BL, 10 ; Divide by 10
Div BL
Add AX, '00' ; Convert to ASCII
Cmp AL, BH ; Check Zero-Blank
Jnz LeadingNonZero
Mov AL, ' ' ; Put in blank instead of zero
LeadingNonZero: Stosw ; Store the two bytes
Mov AL, DH ; Get following character
Stosb ; Store that also
Pop DX
Pop CX
Pop BX
Pop AX
Ret
; Variable length data stored at end
; ----------------------------------
Even
FileSpec1 Label Byte
FileSpec2 equ FileSpec1 + 80
DTABuffer equ FileSpec2 + 80
DisplayString equ DTABuffer + 43
EndOfData equ DisplayString + 81
StackTop equ EndOfData + 200h
CSEG EndS ; End of the segment
End Entry ; Denotes entry point