'===========================================================================
' Subject: GET DIRECTORY DISKSPACE            Date: 08-16-00 (12:25)       
'  Author: Randall L. Glass                   Code: PB                     
'  Origin: rlglass@yahoo.com                Packet: DISK.ABC
'===========================================================================
'----------------------------------------------------------------------------
'                                  DirSize
'                             By Randall L Glass
'                               CopyRight 2000
'
'----------------------------------------------------------------------------
'
' This program is freeware. You may use it anyway you want as long as you
' give me credit in your program or documentation.
'
' This Program looks a directory and subdirectories and adds up the file
' sizes to give you the total amount of space that the directories in that
' directory that up.
'
' This is useful for finding junkfiles and wasted space on your hard drive.
' So you can delete the junk files and compress the files that waste a lot
' of disk space.
'
'--------------------------------------------------------------------------

$CPU 8086                 ' program works on any CPU
$COMPILE EXE              ' compile to an EXE

$ERROR ALL OFF            ' turn off error handling

$STACK  16384             ' use a 16k stack

$OPTION CNTLBREAK OFF     ' don't allow Ctrl-Break to exit program

DEFINT A-Z                ' default all variables to integers for maximum
                          ' speed and minimum size
DECLARE FUNCTION GetStrLoc(BYVAL AllocHandle%) AS LONG

SHARED TotalTreeSize&&, TotalFiles%, TotalDirectories%,Directories%,FileNumber%
SHARED SubDirTreeSize&&, SubFileNumber%, DirFileNumber%, SubDirectories%
SHARED AllocSubDirTreeSize&&,ClusterSize&&,Numberlines%

Drive$ = LEFT$(CURDIR$, 1)                       'get the default drive
Cmd$ = COMMAND$
Directory$ = TRIM$(UCASE$(Cmd$))

FileSpec$  = "*.*"

IF LEN(FileSpec$) = 0 THEN
  PRINT
  PRINT "Usage:  DirSize Directory"
  PRINT "Finds total size of directories"
  PRINT
  END 1
END IF

TempDir$ = ENVIRON$("TEMP")+"\"
REPLACE "\\" WITH "\" IN TempDir$

DiskInfo Drive$,DiskSize&&,Diskfree&&,ClusterSize&&
PRINT
PRINT "Disk Waste Finder"
PRINT "By Randall Glass"
PRINT "Getting Total Size of Directories"
PRINT "Checking Directories for files \";

OPEN TempDir$ +"Dskspace.use" FOR OUTPUT AS #1
DirectorySize&& = DirSize&&(Directory$, FileSpec$)
Numberlines% = 22 - (Numberlilnes% MOD 22)
PRINT #1, STRING$(78,"-")
PRINT #1, LTRIM$(STR$(Directories%)); " Directories";
PRINT #1, ": "  FormatSize$(DirectorySize&&); " in "; STR$(FileNumber%); " Files"
PRINT #1, STRING$(78,"-")
PRINT #1, "Total Directories% = "; STR$(TotalDirectories%); ": ";
PRINT #1, "Total Files ="; STR$(TotalFiles%)
PRINT #1, "Total Size of Directory And SubDirectories = "; FormatSize$(TotalTreeSize&&)
PRINT #1, "Total Allocated Size of Directory And SubDirectories = "; FormatSize$(DiskSize&& -Diskfree&&)
PRINT #1,
PRINT #1, "Disk Size = "; FormatSize$(DiskSize&&)
PRINT #1, "Free Disk Space = "; FormatSize$(Diskfree&&)
PRINT #1, "Disk Cluster Size = "; LTRIM$(USING$("###,###,###",ClusterSize&&)); " Bytes"

FOR I% = 1 TO NumberLines% -10
	PRINT #1,
NEXT I%
CLOSE
PRINT
SHELL "EDIT.COM " + TempDir$ + "Dskspace.use"
END

FUNCTION DirSize&&(StartPath$, FileSpec$) PUBLIC
  DIM SPIN$(3)
  SPIN$(0) = "-"
  SPIN$(1) = "\"
  SPIN$(2) = "|"
  SPIN$(3) = "/"

  DriveNo% = ASCII(UCASE$(StartPath$))
  IF DriveNo% > 63 AND DriveNo% < 91 AND RIGHT$(StartPath$,1) = ":" THEN StartPath$ = StartPath$ + "."

  StartPath$ = TrueName$(StartPath$)

  StartPath$ = StartPath$ + "\"

  REPLACE "\\" WITH "\" IN StartPath$
  REPLACE "//" WITH "/" IN StartPath$

  FileName$ = DIR$(StartPath$ + FileSpec$, 55)

  WHILE LEN(FileName$) > 0
      AllocatedFileSize??? = 0
      DirInfo DirAttrib?,FileSize???
      IF Bit(DirAttrib?,4) AND FileName$ <> "." AND FileName$ <> ".." THEN
		SubFileNumber% = 0
		SubDirectories% = 0
		SubDirTreeSize&& = 0
		AllocatedSubDirSize&& = 0
		AllocSubDirTreeSize&& = 0
		SubDirectorySize&& = SubDirSize&&(StartPath$ + FileName$ + "\", FileSpec$)
		TotalTreeSize&& = TotalTreeSize&& + SubDirectorySize&&
		AllocatedTreeSize&& = AllocatedTreeSize&& + AllocSubDirTreeSize&&
		TotalFiles% = TotalFiles% + SubFileNumber%
                TotalDirectories% = TotalDirectories% + SubDirectories% + 1
                INCR Directories%
                IF (Directories% -1) MOD 19 = 0 THEN
                        PRINT #1, STRING$(78,"-")
			PRINT #1, "Directory  Number Files    AveragSize       Bytes     Allocated Bytes"
                        PRINT #1, STRING$(78,"-")
                END IF
                INCR Numberlines%
                INCR Spin%
                QPRINT SPIN$(Spin% MOD 4)
		PRINT #1, USING$("\        \",FileName$);
                PRINT #1, "  "+USING$("###,###",SubFileNumber%)+"  ";
                IF SubFileNumber% > 0 THEN
                	AverageFileSize&& = SubDirectorySize&&\SubFileNumber%
                	PRINT #1, USING$("###,###,###,###",AverageFileSize&&);
                ELSE
                	PRINT #1, " Not Applicable";
                END IF
                PRINT #1, USING$("###,###,###,###",SubDirectorySize&&);
                PRINT #1, USING$("###,###,###,###",AllocSubDirTreeSize&&)

      ELSEIF ISFALSE Bit(DirAttrib?,3) THEN
                ClusterNumber??? = FileSize???\ClusterSize&&
      		ModSize??? = FileSize??? MOD ClusterSize&&
		IF ModSize??? <> 0 THEN
      			AllocatedFileSize??? = (ClusterNumber??? + 1) * ClusterSize&&
                ELSE
			AllocatedFileSize??? = FileSize???
      		END IF
                'IF FileSize??? = 0 THEN AllocatedFileSize??? = ClusterNumber???
		INCR FileNumber%
		DirectorySize&& = DirectorySize&& + FileSize???
		AllocatedDirSize&& = AllocatedDirSize&& + AllocatedFileSize???
      END IF

      IF INKEY$ = CHR$(27) THEN END  'is escape is pressed
      FileName$ = DIR$
  WEND
  DirSize&& = DirectorySize&&
  TotalTreeSize&& = TotalTreeSize&& + DirectorySize&&
  AllocatedTreeSize&& = AllocatedTreeSize&& + AllocatedDirSize&&
  TotalFiles% = TotalFiles% + FileNumber%


END FUNCTION

FUNCTION SubDirSize&&(Path$, FileSpec$) PUBLIC

  GetDta DtaSeg??,DtaOfs??
  DEF SEG = DtaSeg??
    SubOldDtaBuffer$ = PEEK$(DtaOfs??, 44)    'save current DTA information
  DEF SEG

  FileName$ = DIR$(Path$ + FileSpec$, 55)

  WHILE LEN(FileName$) > 0
      DirInfo DirAttrib?,FileSize???
      IF Bit(DirAttrib?,4) AND FileName$ <> "." AND FileName$ <> ".." THEN
		AllocDirSize&& = 0
		SubDirSize&& Path$ + FileName$ + "\", FileSpec$
		INCR SubDirectories%
      ELSEIF ISFALSE Bit(DirAttrib?,3) THEN
                ClusterNumber??? = FileSize???\ClusterSize&&
      		ModSize??? = FileSize??? MOD ClusterSize&&
		IF ModSize??? <> 0 THEN
      			AllocatedFileSize??? = (ClusterNumber??? + 1) * ClusterSize&&
                ELSE
			AllocatedFileSize??? = FileSize???
      		END IF

                'IF FileSize??? = 0 THEN AllocatedFileSize??? = ClusterNumber???
		INCR SubFileNumber%
		DirectorySize&& = DirectorySize&& + FileSize???
		AllocatedDirSize&& = AllocatedDirSize&& + AllocatedFileSize???
      END IF

      IF INKEY$ = CHR$(27) THEN END  'escape is pressed
      FileName$ = DIR$
  WEND

  DEF SEG = DtaSeg??
    POKE$ DtaOfs??, SubOldDtaBuffer$   'restore saved DTA information
  DEF SEG

  SubDirTreeSize&& =  SubDirTreeSize&& + DirectorySize&&
  AllocSubDirTreeSize&& = AllocSubDirTreeSize&& + AllocatedDirSize&&
  SubDirSize&& = SubDirTreeSize&&

END FUNCTION

'===========================================================================
' Subject: PB DISKINFO V2.5                  Date: 06-21-98 (05:12)
'  Author: Marc van den Dikkenberg           Code: PB
'  Origin: excel@xs4all.nl                 Packet: DISK.ABC
'===========================================================================
DEFINT A-Z

SUB DiskInfo(drive$,DiskSize&&,Diskfree&&,ClusterSize&&) PUBLIC
   Dim Drivename AS String * 4
   Dim Filesysname AS String * 8

   LOCAL Rax??, Rbx??, Rcx??, Rdx??

   Drive$ = ucase$(left$(drive$,1))
   Drivename$ = left$(drive$,1) +":\"+CHR$(0)
   DiskSize&& = 0
   Diskfree&& = 0

   Seg1?? = varseg(drivename)
   Off1?? = varptr(drivename)
   Seg2?? = varseg(filesysname)
   Off2?? = varptr(filesysname)

	! MOV AX,&H71A0
        ! MOV DS,Seg1??
        ! MOV DX,Off1??
        ! MOV ES,Seg2??
        ! MOV DI,Off2??
	! MOV CX,&HFF
	! INT &H21
        ! MOV Rax??,AX
        ! MOV Rbx??,BX

        if Rax?? = &H7100 then
	   ' FAT32 not supported -- Using FAT16 Method instead.
           Driv% = asc(left$(drive$,1))-64
	   ! PUSH DS
	   ! MOV AX,&H3600
	   ! MOV DX,driv%    ; Disk-#  01=A:, 02=B:, etc.
	   ! XOR CX,CX
	   ! XOR BX,DX
	   ! INT &H21
           ! MOV Rax??,ax
           ! MOV Rbx??,bx
           ! MOV Rcx??,cx
           ! MOV Rdx??,dx
	   ! POP DS
           IF Rax?? <> &H0FFFF THEN
              DiskSize&& = Rax?? * Rcx?? * Rdx??
              Diskfree&& = Rax?? * Rbx?? * Rcx??
              ClusterSize&& = Rax?? * Rcx??
           ELSE
               'Disk not found
               Diskfree&& = -1
               Drive$ = chr$(255)
               END IF
        ELSE
	   Dim buffer as String*44
                Seg1?? = varseg(buffer)
                Off1?? = varptr(buffer)
                Seg2?? = varseg(drivename)
                Off2?? = varptr(drivename)

		! PUSH DS
		! MOV AX,&H7303
                ! MOV ds,Seg2??
                ! MOV dx,Off2??
                ! MOV es,Seg1??
                ! MOV di,Off1??
		! MOV CX,128
		! INT &H21
		! POP DS

		if cvwrd(left$(buffer,2))<>0 then
                        ' FAT32
			DiskSize&& = CVDWD(mid$(buffer,9,4)) * CVDWD(mid$(buffer,5,4)) * CVDWD(mid$(buffer,17,4))
                        Diskfree&& = CVDWD(mid$(buffer,9,4)) * CVDWD(mid$(buffer,5,4)) * CVDWD(mid$(buffer,13,4))
                        ClusterSize&& = CVDWD(mid$(buffer,9,4)) * CVDWD(mid$(buffer,5,4))
                else
                        ' Disk not found
                        drive$ = chr$(255)
                        Diskfree&& = -1
		end if
	end if
END SUB

SUB DirInfo(DirAttrib?,DirectorySize???) PUBLIC
  LOCAL DirDate??,DirTime??,DirAttr?,Dsize???
  ! mov  AX, &H2F00              ; function 2Fh, get DTA location
  ! int  &H21                    ; call DOS
  ! MOV  AX,ES:[BX +26]
  ! MOV  DSize???[0],AX
  ! MOV  AX,ES:[BX +28]
  ! MOV  DSize???[2],AX
  ! MOV  AL,ES:[BX +21]
  ! MOV  DirAttr?,AL
  DirectorySize??? = DSize???
  DirAttrib? = DirAttr?
END SUB

SUB GetDTA(DtaSeg??, DtaOfs??) PUBLIC
  ! push DS 
  ! mov  AX, &H2F00              ; function 2Fh, get DTA location
  ! int  &H21                    ; call DOS
  ! lds  SI, DtaSeg??            ; point DS:SI at DtaSeg
  ! mov  DS:[SI], ES             ; put segment of DTA in variable
  ! lds  SI, DtaOfs??            ; point DS:SI at DtaOfs
  ! mov  DS:[SI], BX             ; put offset of DTA in variable
  ! pop  DS
END SUB

FUNCTION FormatSize$(Bytes&&)
IF Bytes&& > 3999999 THEN
        FormatSize$ = LTRIM$(USING$("###,###,###.##",Bytes&&/1000000))+" Megabytes"
ELSEIF Bytes&& > 999999 THEN
        FormatSize$ = LTRIM$(USING$("###,###,###,###,###.##",Bytes&&/1000))+" Kilobytes"
ELSE
        FormatSize$ = LTRIM$(USING$("###,###,###,###,###",Bytes&&))+" Bytes"
END IF
END FUNCTION

FUNCTION TrueName$(Directory$)
REPLACE "\\" WITH "\" IN Directory$
REPLACE "//" WITH "/" IN Directory$
DIM Canonicalized AS STRING * 128
DirName$ = Directory$ +CHR$(0)
DirNamePtr??? = STRPTR32(DirName$)
CanonicalizedPtr??? = VARPTR32(Canonicalized$)
DosError?? = 0

!PUSH DS
!LDS SI,DirNamePtr???
!LES DI,CanonicalizedPtr???
!MOV AH,&H60
!INT &H21
!POP DS

!JNC NoError
!MOV DosError??,AX
NoError:
IF LEFT$(Canonicalized$,2) = "\\" THEN
        Drive$ = MID$(Canonicalized$,3,1)+":"
        Path$ = EXTRACT$(MID$(Canonicalized$,8),CHR$(0))
        IF Path$ = "" THEN Path$ = "\"
	FUNCTION = EXTRACT$(Drive$ +Path$,CHR$(0))
ELSE
FUNCTION = EXTRACT$(Canonicalized$,CHR$(0))
END IF
END FUNCTION

SUB QPRINT(Txt$) PUBLIC
 ! LES     BX,Txt$
 ! MOV     AX,ES:[BX]
 ! PUSH    AX
 ! CALL    GetStrLoc
 ! JCXZ    Quit
 ! MOV     ES, DX
 ! MOV     SI, AX
 ! MOV     AH,&H0E
 ! MOV     BH,PbvScrnVpage
 ! MOV     BL,7
 Printit:
 ! MOV     AL,ES:[SI]
 ! INT     &H10
 ! INC     SI
 ! LOOP    Printit
Quit:
END SUB
