home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / drchk034.zip / drivechk.cmd next >
OS/2 REXX Batch file  |  1996-11-27  |  55KB  |  1,564 lines

  1. /**********************************************************************/
  2. /*                                                                    */
  3. /*  DriveCheck v0.034                                                 */
  4. /*                                                                    */
  5. /*  Written by Mike Ruskai <thanny@ibm.net>                           */
  6. /*                                                                    */
  7. /*  Distribute and modify freely, but it'd be nice if you give me     */
  8. /*  credit if you distribute a modified form.                         */
  9. /*                                                                    */
  10. /*  Usage:  DRIVECHK.CMD [/T] [<drive letter>: [/S|/N]                */
  11. /*          [/O:<filename>|/C]]                                       */
  12. /*                                                                    */
  13. /*  Parameters are optional.  <drive letter>: is self explanatory.    */
  14. /*  The /S switch tells the program skip extended attributes, and     */
  15. /*  can only be used when the drive letter is passed.  Using /N in    */
  16. /*  its place indicates that EA's should be tallied.  The /O switch   */
  17. /*  tells the program to write the report to <filename>.  Using /C    */
  18. /*  in its place indicates that output should go to the CON device.   */
  19. /*  If /S|/N or /O|/C aren't used, the program will prompt for a      */
  20. /*  course of action concerning EA's and the display of results.      */
  21. /*  A valid drive letter must be either the first or second           */
  22. /*  argument.  The /T switch has the sole purpose of forcing text     */
  23. /*  mode operation, instead of Visrual REXX (if present).  It is      */
  24. /*  independant on the presence of a drive letter.                    */
  25. /*                                                                    */
  26. /*  This REXX script will scan an entire drive to determine how much  */
  27. /*  space would be wasted for your specific files with the HPFS and   */
  28. /*  FAT file systems.  The display of this information depends on     */
  29. /*  which file system is actually being used.                         */
  30. /*                                                                    */
  31. /*  I've tried to include as much information as I know how.  In      */
  32. /*  addition to the normal file system usage for a file and a         */
  33. /*  directory, the extended attributes are also added up and used     */
  34. /*  in space and slack space determinations.  For files that do not   */
  35. /*  have any extended attributes, the size of the Fnode (512 bytes)   */
  36. /*  for the HPFS scenario is added to the slack space for the file,   */
  37. /*  since it would not exist in the FAT scenario.  That also goes     */
  38. /*  for zero-byte files, which take up 512 bytes on HPFS drives, but  */
  39. /*  zero bytes on FAT drives.                                         */
  40. /*                                                                    */
  41. /*  What's *not* included is the space consumed by the system areas   */
  42. /*  specific to the file system.  The reason for this exclusion is    */
  43. /*  that I don't know how to measure this size for HPFS volumes       */
  44. /*  without capturing the output of CHKDSK (time-consuming), since I  */
  45. /*  see no correlation between system area size and total disk size.  */
  46. /*  My own HPFS drives have system areas ranging from 2MB to 6.5MB,   */
  47. /*  with smaller drives sometimes having bigger system areas than     */
  48. /*  some larger drives.                                               */
  49. /*                                                                    */
  50. /*  As stated, extended attributes are included, but the process by   */
  51. /*  which they are is quite slow.  The only way via REXX to find the  */
  52. /*  size of a file's extended attributes was to use the output of     */
  53. /*  CMD.EXE or 4OS2.EXE's DIR command (using the /N parameter on FAT  */
  54. /*  volumes).  Piping the output to RXQUEUE was very slow, and        */
  55. /*  redirecting the output to a file, then reading from the file was  */
  56. /*  much faster, but still slow.  4OS2.EXE tends to be about 60%      */
  57. /*  slower than CMD.EXE in loading itself into memory (more features  */
  58. /*  to load).  This would normally prompt you to type CMD before      */
  59. /*  running this, given the frequency with which the interpreter is   */
  60. /*  called (if you knew this about CMD and 4OS2, that is), but here,  */
  61. /*  you needn't bother.  Because of some extra work necessitated by   */
  62. /*  the output of CMD, the speed balances out - both CMD and 4OS2     */
  63. /*  are equally snail-like in this process.  Because of the horrible  */
  64. /*  speed, you might want to skip EA checking altogether.  The        */
  65. /*  significance of EA's in space determinations vary from drive to   */
  66. /*  drive, though.  If you know that your files have quite a lot of   */
  67. /*  extended attributes, you should just suffer to get results which  */
  68. /*  more accurately represent reality.                                */
  69. /*                                                                    */
  70. /*  A new consideration is 32-bit 4OS2.  Due to a bug in the 32-bit   */
  71. /*  OS/2 API, extended attributes sizes are reported at twice their   */
  72. /*  actual value.  4OS2 gets around this by halving the returned      */
  73. /*  result, but this only works up to 32k.  This is because the API   */
  74. /*  call returns a maximum value of 64k, which is the maximum size    */
  75. /*  of a file's EA.  16-bit CMD and 4OS2 do not have this problem.    */
  76. /*  If you want to get accurate EA counts, you should use one of      */
  77. /*  these, by typing CMD or 4OS2-16 before running DriveCheck.        */
  78. /*                                                                    */
  79. /*  The output of the program is either plain text or graphical       */
  80. /*  using the IBM EWS program Visual REXX.  You must have VREXX on    */
  81. /*  your system for the graphical method to work.                     */
  82. /*                                                                    */
  83. /*  Both interfaces show scan progress, and at the end provide a      */
  84. /*  report on usage along with a conclusion about which file system   */
  85. /*  would be more space-efficient for your drive.  They also provide  */
  86. /*  simple bar graphs that show used, wasted, and free space for the  */
  87. /*  drive with both file systems.                                     */
  88. /*                                                                    */
  89. /**********************************************************************/
  90.  
  91. call RxFuncAdd 'SysLoadFuncs','RexxUtil','SysLoadFuncs'
  92. call SysLoadFuncs
  93.  
  94. /* Sets digits to allow for large numbers, so that those of you with  */
  95. /* the big drives don't get a mess in the reported number.  Using 12  */
  96. /* digits guarantees that even if HPFS's theoretical limit of 512GB   */
  97. /* is implemented, the number will look alright (provided something   */
  98. /* odd doesn't happen to turn it into a fractional number, should it  */
  99. /* be larger than 4,294,967,296 - unless REXX can somehow use more    */
  100. /* than a 32-bit unsigned integer).                                   */
  101.  
  102. numeric digits 12
  103.  
  104. /* To prevent VREXX from remaining after a crash of some sort, all    */
  105. /* errors will result in it being deinitialized before exiting the    */
  106. /* program.                                                           */
  107.  
  108. signal on halt
  109. signal on error
  110. signal on syntax
  111. signal on failure
  112.  
  113. /* Checks whether or not to skip using Visual REXX, and independently */
  114. /* whether other parameters were given.  If only /T is passed, the    */
  115. /* program will run interactively in text-mode.  With no parameters,  */
  116. /* it will run interactively with graphical dialogs using Visual REXX */
  117. /* if it is present on the system.                                    */
  118.  
  119. DCVer='0.034'
  120. CurrDir=directory()
  121. parse version rexxver
  122. if word(rexxver,1)='OBJREXX' then orexx=1
  123. else orexx=0
  124.  
  125. arg par1 par2 par3 par4
  126.  
  127. if par1='?'|par1='/?'|translate(par1)='/H' then signal Usage
  128.  
  129. if translate(par1)='/T' then do
  130.     TestDrive=par2
  131.     SkipSwitch=par3
  132.     OutFile=par4
  133.     Visual=0
  134. end
  135. else do
  136.     TestDrive=par1
  137.     SkipSwitch=par2
  138.     OutFile=par3
  139.     TestVis=1
  140. end
  141. if TestVis=1 then do
  142.     signal on syntax name vrtrap
  143.     success=VInit()
  144.     if success='ERROR' then Visual=0
  145.     else Visual=1
  146. end
  147.  
  148. vrtrap:
  149. if Visual\=1 then Visual=0
  150. signal on syntax name syntax
  151.  
  152. /* Finds the INI file, if it exists, and digs out the colors to use   */
  153. /* for the graphs.  If the file is "corrupt", it will use default     */
  154. /* colors.                                                            */
  155.  
  156. if Visual=1 then do
  157.  
  158.     parse source SourceString
  159.     SourceFile=word(SourceString,3)
  160.     SourceDrive=filespec('drive',SourceFile)
  161.     SourcePath=filespec('path',SourceFile)
  162.     SourceDir=SourceDrive||SourcePath
  163.     call directory SourceDir
  164.     INIfile='drivechk.ini'
  165.     check=stream(INIfile,'c','query exists')
  166.     if check='' then defaults=1
  167.     else do
  168.     
  169.         cc=translate(linein(INIfile))
  170.         ccheck=ColorCheck(cc)
  171.         if ccheck=1 then MainColor=cc
  172.         else MainColor='WHITE'
  173.         cc=translate(linein(INIfile))
  174.         ccheck=ColorCheck(cc)
  175.         if ccheck=1 then MainTextColor=cc
  176.         else MainTextColor='BLACK'
  177.  
  178.         cc=translate(linein(INIfile))
  179.         ccheck=ColorCheck(cc)
  180.         if ccheck=1 then DirColor=cc
  181.         else DirColor='CYAN'
  182.         cc=translate(linein(INIfile))
  183.         ccheck=ColorCheck(cc)
  184.         if ccheck=1 then DirTextColor=cc
  185.         else DirTextColor='BLACK'
  186.   
  187.         cc=translate(linein(INIfile))
  188.         ccheck=ColorCheck(cc)
  189.         if ccheck=1 then FileColor=cc
  190.         else FileColor='CYAN'
  191.         cc=translate(linein(INIfile))
  192.         ccheck=ColorCheck(cc)
  193.         if ccheck=1 then FileTextColor=cc
  194.         else FileTextColor='BLACK'
  195.  
  196.         cc=translate(linein(INIfile))
  197.         ccheck=ColorCheck(cc)
  198.         if ccheck=1 then GraphColor=cc
  199.         else GraphColor='BLACK'
  200.         cc=translate(linein(INIfile))
  201.         ccheck=ColorCheck(cc)
  202.         if ccheck=1 then GraphTextColor=cc
  203.         else GraphTextColor='WHITE'
  204.  
  205.         cc=translate(linein(INIfile))
  206.         ccheck=ColorCheck(cc)
  207.         if ccheck=1 then FreeColor=cc
  208.         else FreeColor='WHITE'
  209.         cc=translate(linein(INIfile))
  210.         ccheck=ColorCheck(cc)
  211.         if ccheck=1 then UsedColor=cc
  212.         else UsedColor='GREEN'
  213.         cc=translate(linein(INIfile))
  214.         ccheck=ColorCheck(cc)
  215.         if ccheck=1 then WasteColor=cc
  216.         else WasteColor='RED'
  217.         
  218.         res=translate(linein(INIfile))
  219.         rcheck=ResCheck(res)
  220.         if rcheck=1 then ScrRes=res
  221.         else ScrRes='640X480'
  222.     end
  223.     if defaults=1 then do
  224.         MainColor='WHITE'
  225.         MainTextColor='BLACK'
  226.         DirColor='CYAN'
  227.         DirTextColor='BLACK'
  228.         FileColor='CYAN'
  229.         FileTextColor='BLACK'
  230.         GraphColor='BLACK'
  231.         GraphTextColor='WHITE'
  232.         FreeColor='WHITE'
  233.         UsedColor='GREEN'
  234.         WasteColor='RED'
  235.         ScrRes='640X480'
  236.     end   
  237.  
  238. /* Sets the variables for different screen resolutions based on what  */
  239. /* was in the INI file.                                               */
  240.  
  241.     if ScrRes='640X480' then do
  242.         FileDiagWidth=30
  243.         FontSize=16
  244.         TopText=960
  245.         TextSpace=38
  246.         DirListEnd=365
  247.         StatsHalfTwo=515
  248.         TopKey=890
  249.         BottomKey=825
  250.         KeyName=845
  251.         GraphLeft=12
  252.         GraphBottom=30
  253.         GraphRight=65
  254.         GraphTop=85
  255.         GTopText=930
  256.         GraphTopOne=760
  257.         GraphTopTwo=350
  258.         GraphTextOne=480
  259.         GraphTextTwo=50
  260.     end
  261.  
  262.     if ScrRes='800X600' then do
  263.         FileDiagWidth=28
  264.         FontSize=14
  265.         TopText=965
  266.         TextSpace=38
  267.         DirListEnd=320
  268.         StatsHalfTwo=450
  269.         TopKey=905
  270.         BottomKey=845
  271.         KeyName=860
  272.         GraphLeft=15
  273.         GraphBottom=40
  274.         GraphRight=60
  275.         GraphTop=80
  276.         GTopText=940
  277.         GraphTopOne=775
  278.         GraphTopTwo=360
  279.         GraphTextOne=485
  280.         GraphTextTwo=50
  281.     end
  282.  
  283.     if ScrRes='1024X768' then do
  284.         FileDiagWidth=25
  285.         FontSize=14
  286.         TopText=970
  287.         TextSpace=35
  288.         DirListEnd=325
  289.         StatsHalfTwo=460
  290.         TopKey=905
  291.         BottomKey=850
  292.         KeyName=860
  293.         GraphLeft=15
  294.         GraphBottom=40
  295.         GraphRight=60
  296.         GraphTop=80
  297.         GTopText=940
  298.         GraphTopOne=775
  299.         GraphTopTwo=360
  300.         GraphTextOne=485
  301.         GraphTextTwo=50
  302.     end
  303.  
  304.     if ScrRes='1280X1024' then do
  305.         FileDiagWidth=25
  306.         FontSize=14
  307.         TopText=970
  308.         TextSpace=33
  309.         DirListEnd=325
  310.         StatsHalfTwo=470
  311.         TopKey=900
  312.         BottomKey=855
  313.         KeyName=860
  314.         GraphLeft=15
  315.         GraphBottom=40
  316.         GraphRight=60
  317.         GraphTop=80
  318.         GTopText=945
  319.         GraphTopOne=765
  320.         GraphTopTwo=350
  321.         GraphTextOne=480
  322.         GraphTextTwo=50
  323.     end
  324.  
  325.     if ScrRes='1600X1200' then do
  326.         FileDiagWidth=24
  327.         FontSize=16
  328.         TopText=970
  329.         TextSpace=32
  330.         DirListEnd=305
  331.         StatsHalfTwo=435
  332.         TopKey=905
  333.         BottomKey=860
  334.         KeyName=865
  335.         GraphLeft=15
  336.         GraphBottom=40
  337.         GraphRight=60
  338.         GraphTop=80
  339.         GTopText=940
  340.         GraphTopOne=775
  341.         GraphTopTwo=360
  342.         GraphTextOne=485
  343.         GraphTextTwo=50
  344.     end
  345.  
  346. end
  347.  
  348. /* If using Visual REXX, the main window is now drawn with some info  */
  349. /* written into it.                                                   */
  350.  
  351. if Visual=1 then do
  352.     title='DriveCheck v'||DCVer
  353.     mpos.left=20
  354.     mpos.bottom=10
  355.     mpos.right=80
  356.     mpos.top=90
  357.     MainID=VOpenWindow(title,MainColor,mpos)
  358.     call VForeColor MainID,MainTextColor
  359.     call VSetFont MainID,'TIME',FontSize
  360.     iline.1="DriveCheck v"||DCVer||" is a program written in REXX that"
  361.     iline.2="scans each file on the drive you specify to determine how"
  362.     iline.3="much slack space it is wasting.  Slackspace is the difference"
  363.     iline.4="between the size of the file and how much space is allocated"
  364.     iline.5="to it on the hard drive."
  365.     iline.6=""
  366.     iline.7="FAT formatted drives have more slack space per file than HPFS"
  367.     iline.8="formatted drives because of the way each file system"
  368.     iline.9="allocates space.  The difference in slack space between the"
  369.     iline.10="two file systems increases with each doubling of the drive"
  370.     iline.11="size, starting from 16MB (below 16MB, FAT changes so that"
  371.     iline.12="the per-file waste is equivalent to that of a drive between"
  372.     iline.13="128MB and 256MB in size).  This program will show you"
  373.     iline.14="exactly what the different file systems would waste on the"
  374.     iline.15="drive you specify, with the current mix of files."
  375.     iline.16=""
  376.     iline.17="DriveCheck may be modified and distributed freely, but it"
  377.     iline.18="would be nice if you gave credit where credit is due if"
  378.     iline.19="you make any changes to it and distribute that modified"
  379.     iline.20="form (though I can't forsee a reason for this)."
  380.     iline.21=""
  381.     iline.22="I'd appreciate any comments about the program, which you"
  382.     iline.23="can direct to:"
  383.     iline.24=""
  384.     iline.25="mruskai@microfone.net"
  385.     iline.26="Mike Ruskai 1:107/634@fidonet"
  386.     PosY=TopText
  387.     do i=1 to 26
  388.         call VSay MainID,15,PosY,iline.i
  389.         PosY=PosY-TextSpace
  390.     end
  391.     call VDialogPos 50,50
  392. end
  393.  
  394. /* Processes the command-line arguments, asking for input if it is    */
  395. /* necessary.                                                         */
  396.  
  397. if TestDrive\='' then do
  398.     if directory(TestDrive||'\')\=TestDrive||'\' then do
  399.         say 'Invalid drive, '||'"'TestDrive'"'||'.'
  400.         say ''
  401.         say 'Type DRIVECHK /? for usage.'
  402.         exit
  403.     end
  404.     else call directory CurrDir
  405. end
  406. else do
  407.     if Visual=1 then do
  408.         drives=SysDriveMap('C','USED')
  409.         numdrv=words(drives)
  410.         dnum=0
  411.         do i=1 to numdrv
  412.             chkdrv=word(drives,i)
  413.             chkwrt=lineout(chkdrv||'\test.txt','Testing')
  414.             if chkwrt=0 then do
  415.                 dnum=dnum+1
  416.                 dlabel=subword(SysDriveInfo(chkdrv),4)
  417.                 if dlabel='' then label=''
  418.                 else label='<'||dlabel||'>'
  419.                 drive.dnum=chkdrv||'    '||label
  420.                 call stream chkdrv||'\test.txt','c',close
  421.                 call SysFileDelete chkdrv||'\test.txt'
  422.             end
  423.         end
  424.         drive.0=dnum
  425.         if dnum>10 then height=10
  426.         else if dnum<4 then height=dnum
  427.         else if dnum<7 then height=dnum-1
  428.         else height=dnum-2
  429.         call VListBox 'Drive Selection',drive,FileDiagWidth,height,1
  430.         TestDrive=substr(drive.vstring,1,2)
  431.     end
  432.     else do until ans=1
  433.         call SysCls
  434.         if ans=0 then do
  435.             call SysCurPos 8,0
  436.             say '"'TestDrive'"'||', is an invalid drive.'
  437.         end
  438.         call SysCurPos 10,0
  439.         say 'Which drive do you wish to check (e.g. C)?'
  440.         call charout ,': '
  441.         TDrive=translate(SysGetKey('echo'))
  442.         TestDrive=TDrive||':'        
  443.         if directory(TestDrive||'\')\=TestDrive||'\' then ans=0
  444.             else ans=1
  445.     end
  446. end
  447. if SkipSwitch\='' then do
  448.     if translate(SkipSwitch)='/S' then SkipEA=1
  449.     else if translate(SkipSwitch)='/N' then SkipEA=0
  450.     else if translate(substr(SkipSwitch,1,3))='/O:' then do
  451.         OutFile=SkipSwitch
  452.         SkipEA=0
  453.     end
  454.     else do
  455.         say 'Invalid skip switch or outfile option.'
  456.         say ''
  457.         say 'Type DRIVECHK /? for usage.'
  458.         exit
  459.     end
  460. end
  461. else do
  462.     ans=2
  463.     if Visual=1 then do
  464.         msg.0=1
  465.         msg.1='  Do you wish to skip EA checking?'
  466.         ans=VMsgBox('EA Skipping',msg,6)
  467.         if ans='YES' then SkipEA=1
  468.         else SkipEA=0
  469.     end
  470.     else do until ans=1
  471.         call SysCls
  472.         if ans=0 then do
  473.             call SysCurPos 8,0
  474.             say "Please answer only with 'Y' or 'N'."
  475.         end
  476.         call SysCurPos 10,0
  477.         say 'Do you wish to skip EA checking? (Y/N)'
  478.         call charout ,': '
  479.         res=translate(SysGetKey('echo'))
  480.         if res\='Y' & res\='N' then ans=0
  481.         else do
  482.             ans=1
  483.             if res='Y' then SkipEA=1
  484.             else SkipEA=0
  485.         end
  486.     end
  487. end
  488. if OutFile\='' then do
  489.     if translate(OutFile)='/C' then OutFile='CON'
  490.     else if translate(substr(OutFile,1,3))\='/O:' then do
  491.         say 'Invalid outfile option.'
  492.         say ''
  493.         say 'Type DRIVECHK /? for usage.'
  494.         exit
  495.     end
  496.     else do
  497.         OutFile=substr(OutFile,4)                                      
  498.         if substr(OutFile,2,1)\=':' then do                            
  499.             if pos('\',OutFile)=0 then                                 
  500.                 OutFile=CurrDir||'\'||OutFile                          
  501.             else if pos('\',OutFile)=1 then                            
  502.                 OutFile=left(CurrDir,2)||OutFile                       
  503.                 else OutFile=CurrDir||'\'||OutFile                     
  504.         end                                                            
  505.         check=lineout(OutFile,'1')                                     
  506.         if check\=0 then do                                            
  507.             say 'Invalid outfile option, '||OutFile                    
  508.             say ''                                                     
  509.             say 'Type DRIVECHK /? for usage.'                          
  510.             exit                                                       
  511.         end                                                            
  512.         else do                                                        
  513.             call stream OutFile,'c','close'                            
  514.             call SysFileDelete OutFile                                 
  515.         end                                                            
  516.     end                                                                
  517. end
  518. else do
  519.     ans=2
  520.     if Visual=1 then do until confirm=1
  521.         msg.0=1
  522.         msg.1='Do you wish to save the results to a file?'
  523.         filech=VMsgBox('Output Choice',msg,6)
  524.         if filech='YES' then do 
  525.             click=VFileBox('File to save results to','',log)
  526.             if click='CANCEL' then confirm=0
  527.             else do
  528.                 logfile=log.vstring
  529.                 check=lineout(logfile,'check')
  530.                 if check=1 then do
  531.                     msg.0=1
  532.                     msg.1='Invalid filename chosen.'
  533.                     call VMsgBox 'Invalid Filename',msg,1
  534.                     confirm=0
  535.                 end
  536.                 else do
  537.                     call stream logfile,'c','close'
  538.                     call SysFileDelete logfile
  539.                     msg.0=1
  540.                     msg.1='Save results to '||logfile||'?'
  541.                     ans=VMsgBox('Confirmation',msg,3)
  542.                     if ans='OK' then do
  543.                         OutFile=logfile
  544.                         confirm=1
  545.                     end
  546.                 end
  547.             end
  548.         end
  549.         else do
  550.             OutFile='CON'
  551.             confirm=1
  552.         end
  553.     end       
  554.     else do until ans=1
  555.         call SysCls
  556.         if ans=0 then do
  557.             call SysCurPos 8,0
  558.             say "Please answer only with 'Y' or 'N'."
  559.         end
  560.         call SysCurPos 10,0
  561.         say 'Do you wish to direct output to a file? (Y/N)'
  562.         call charout ,': '
  563.         res=translate(SysGetKey('echo'))
  564.         if res\='Y' & res\='N' then ans=0
  565.             else do
  566.                 ans=1
  567.                 if res='Y' then GetOF=1
  568.                 else OutFile='CON'
  569.             end
  570.     end
  571.     if GetOF=1 then do
  572.         ans=2
  573.         do until ans=1
  574.             call SysCls
  575.             if ans=0 then do
  576.                 call SysCurPos 8,0
  577.                 say '"'OFName'"'||' is not a valid filename.'
  578.             end
  579.             call SysCurPos 10,0
  580.             say 'Enter the name for the output file.'
  581.             call charout ,': '
  582.             parse pull OFName
  583.             if substr(OFName,2,1)\=':' then do
  584.                 if pos('\',OutFile)=0 then 
  585.                     OFName=CurrDir||'\'||OFName
  586.                 else if pos('\',OFName)=1 then
  587.                     OFName=left(CurrDir,2)||OFName
  588.                     else OFName=CurrDir||'\'||OFName
  589.             end
  590.             check=lineout(OFName,'1')
  591.             if check\=0 then ans=0
  592.             else do
  593.                 OutFile=OFName
  594.                 call stream OFName,'c','close'
  595.                 call SysFileDelete OFName
  596.                 do until ans2=1
  597.                     call SysCls
  598.                     if ans2=0 then do
  599.                         call SysCurPos 8,0
  600.                         say "Please answer only with 'Y' or 'N'."
  601.                     end
  602.                     call SysCurPos 10,0
  603.                     say 'Use '||'"'OutFile'"'||' for output? (Y/N)'
  604.                     call charout ,': '
  605.                     res=translate(SysGetKey('echo'))
  606.                     if res\='Y' & res\='N' then ans2=0
  607.                     else do
  608.                         ans2=1
  609.                         if res='Y' then ans=1
  610.                         else ans=2
  611.                     end
  612.                 end
  613.             end
  614.         end
  615.     end
  616. end
  617.  
  618. call directory TestDrive||'\'
  619.  
  620. /* Uses the total drive space as reported by SysDriveInfo to deter-   */
  621. /* mine the cluster size that FAT would use on the drive.  It then    */
  622. /* attempts to write a file with a long name to determine if the      */
  623. /* drive being scanned is HPFS or FAT, and orders the allocation unit */
  624. /* variables accordingly (affects report at program conclusion).      */
  625.  
  626. DriveSize=word(SysDriveInfo(TestDrive),3)
  627. if DriveSize<16777216 then ClustSize=4096
  628. else do
  629.     if DriveSize>=16777216 & DriveSize<134217728 then ClustSize=2048
  630.     else do
  631.         RawClusterSize=format((DriveSize/65536),,0)
  632.         BinClust=x2b(d2x(RawClusterSize))
  633.         ValidPartStart=pos('1',BinClust)
  634.         DigitValue=length(substr(BinClust,ValidPartStart))
  635.         ClustSize=2**DigitValue
  636.     end
  637. end
  638. tfile='Testing For HPFS File System'
  639. rc=lineout(tfile,'test')
  640. if rc=1 then do
  641.     FileSystem.1='FAT'
  642.     FileSystem.2='HPFS'
  643.     AUnit.1=ClustSize
  644.     AUnit.2=512
  645.     Fnode.1=0
  646.     Fnode.2=512
  647. end
  648. else do
  649.     FileSystem.1='HPFS'
  650.     FileSystem.2='FAT'
  651.     call stream tfile,'c','close'
  652.     call SysFileDelete tfile
  653.     AUnit.1=512
  654.     AUnit.2=ClustSize
  655.     Fnode.1=512
  656.     Fnode.2=0
  657. end
  658.  
  659. /* Quick check to see if CMD.EXE or 4OS2.EXE is being used.  It has   */
  660. /* an effect on how EA size checking is done, since the display for   */
  661. /* each command processor is slightly different.                      */
  662. /* Note also that if you are using CMD.EXE, you will have to switch   */
  663. /* to the desktop manually to interact with the VREXX components.     */
  664. /* I do not know the source of the problem.                           */
  665.  
  666. p1=right(d2x(random(65535)),4,'0')
  667. p2=right(d2x(random(65535)),4,'0')
  668. TShChk='\'||p1||p2||'.TMP'
  669. '@ver>'||TShChk
  670. call SysFileSearch '4OS2',TShChk,'ShCheck.'
  671. call stream TShChk,'c','close'
  672. call SysFileDelete TShChk
  673. if ShCheck.0=0 then UShell='CMD'
  674.     else UShell='4OS2'
  675.  
  676. /* Initializes the variables used for the main procedure.             */
  677.  
  678. crlf='0d0a'x
  679. TotFiles=0
  680. TotSize=0
  681. TotDirs=0
  682. TotWaste.1=0
  683. TotWaste.2=0
  684. TotDirSize.1=0
  685. TotDirSize.2=0
  686.  
  687. /* Uses CMD.EXE or 4OS2.EXE to get a quick list of all subdirectories */
  688. /* on the drive for the computation of their space consumption, and   */
  689. /* that of the files they contain.  If Visual REXX is in use, the     */
  690. /* directory window and file window are drawn, and the scanning       */
  691. /* begins.                                                            */
  692.  
  693. if Visual=1 then do
  694.     title='DriveCheck v'||DCVer||' scanning drive '||TestDrive
  695.     call VSetTitle MainID,title
  696.     title='Current scan directory'
  697.     dpos.left=15
  698.     dpos.bottom=57
  699.     dpos.right=50
  700.     dpos.top=63
  701.     DirID=VOpenWindow(title,DirColor,dpos)
  702.     call VForeColor DirID,DirTextColor
  703.     call VSetFont DirID,'TIME',FontSize
  704.     title='Current scan file'
  705.     fpos.left=15
  706.     fpos.bottom=37
  707.     fpos.right=50
  708.     fpos.top=43
  709.     FileID=VOpenWindow(title,FileColor,fpos)
  710.     call VForeColor FileID,FileTextColor
  711.     call VSetFont FileID,'TIME',FontSize
  712.     call VSay DirID,5,500,TestDrive||'\'
  713. end
  714. else do
  715.     call SysCls
  716.     ClrStr="                                  "
  717.     ClrStr=ClrStr||ClrStr||' '
  718.     call SysCurPos 12,0
  719.     call charout ,'Scanning : '||TestDrive||'\'
  720. end
  721. Data=ProcDir(TestDrive||'\')
  722. TotSize=TotSize+word(Data,3)
  723. do i=1 to 2
  724.     TotWaste.i=TotWaste.i+word(Data,i)
  725.     TotDirSize.i=TotDirSize.i+AUnit.i
  726. end
  727. TotFiles=TotFiles+word(Data,4)
  728. p1=right(d2x(random(65535)),4,'0')
  729. p2=right(d2x(random(65535)),4,'0')
  730. TDList='\'||p1||p2||'.TMP'
  731. if Visual=1 then do
  732.     str='Getting list of directories... '
  733.     call VForeColor MainID,MainTextColor
  734.     call VClearWindow MainID
  735.     call VSay MainID,5,TopText,str
  736. end
  737. else do
  738.     call SysCurPos 10,0
  739.     call SysCurState 'off'
  740.     call charout ,"Getting list of directories... "
  741. end
  742. if UShell='4OS2' then do
  743.     signal off error
  744.     '*@dir/b/ad/s > '||TDList
  745.     signal on error
  746. end
  747. else '@dir/f/ad/s >'||TDList
  748. if Visual=1 then do
  749.     str='Done'
  750.     call VSay MainID,DirListEnd,TopText,str
  751. end
  752. else call charout ,"Done"
  753. check=lines(TDList)
  754. if Visual\=1 then do    
  755.     call SysCurPos 12,0
  756.     call charout ,'Scanning : '
  757. end
  758. do while lines(TDList)>0
  759.     WDir=linein(TDList)
  760.     if length(WDir)>68 then 
  761.         DDir=left(WDir,68)||'>'
  762.     else
  763.         DDir=WDir
  764.     if Visual=1 then do
  765.         call VClearWindow DirID
  766.         str=WDir
  767.         call VSay DirID,5,500,str
  768.     end
  769.     else do
  770.         call SysCurPos 12,11
  771.         call charout ,ClrStr
  772.         call SysCurPos 12,11
  773.         call charout ,DDir
  774.     end
  775.     TotDirs=TotDirs+1
  776.     Data=ProcDir(WDir)
  777.     TotSize=TotSize+word(Data,3)
  778.     do i=1 to 2
  779.         TotWaste.i=TotWaste.i+word(Data,i)
  780.         TotDirSize.i=TotDirSize.i+AUnit.i
  781.     end
  782.     TotFiles=TotFiles+word(Data,4)
  783.     DEAData=TallyDirEA(WDir)
  784.     do i=1 to 2
  785.         TotDirSize.i=TotDirSize.i+word(DEAData,i)
  786.     end
  787.     if orexx=1 then call SysSleep 0.005
  788. end
  789. call stream TDList,'c','close'
  790. call SysFileDelete TDList
  791.  
  792. do i=1 to 2
  793.     TotFree.i=DriveSize-(TotSize+TotDirSize.i+TotWaste.i)
  794. end
  795. AllWaste=TotWaste.1-TotWaste.2
  796. AllDir=TotDirSize.1-TotDirSize.2
  797. AllTot=AllWaste+AllDir
  798. if AllTot>=0 then 
  799.     if AllTot=0 then
  800.         TotalDiff=0
  801. else do
  802.     Modifier='*LOST*'
  803.     TotalDiff=abs(AllTot)
  804. end
  805. else do
  806.     Modifier='*SAVED*'
  807.     TotalDiff=abs(AllTot)
  808. end
  809.  
  810. if Visual\=1 then do
  811.     if OutFile='CON' then do
  812.         call SysCurPos 16,0
  813.         call lineout ,'Press any key for statistics...'
  814.         scrap=SysGetKey('noecho')
  815.     end
  816. end
  817.  
  818. /* Reports the data in a formatted manner.  Each of the numerical     */
  819. /* variables is deliminated with via the CoDel procedure.  Then the   */
  820. /* screen is cleared, data presented, and conclusion stated.          */
  821.  
  822. FormDriveSize=CoDel(DriveSize)
  823. FormTotalDiff=CoDel(TotalDiff)
  824. do i=1 to 2
  825.     FormDirSpace.i=CoDel(TotDirSize.i)
  826.     FormWasteSpace.i=CoDel(TotWaste.i)
  827.     FormUnitSize.i=CoDel(AUnit.i)
  828.     FormTotFree.i=CoDel(TotFree.i)
  829. end
  830. FormTotSize=CoDel(TotSize)
  831. FormTotFiles=CoDel(TotFiles)
  832. FormTotDirs=CoDel(TotDirs)
  833.  
  834. do i=1 to 2
  835.     PercentFree.i=(TotFree.i/DriveSize)*100
  836.     PercentUsed.i=((TotDirSize.i+TotSize)/DriveSize)*100
  837.     PercentWaste.i=(TotWaste.i/DriveSize)*100
  838.     fPercentFree.i=format(PercentFree.i,,2)
  839.     fPercentUsed.i=format(PercentUsed.i,,2)
  840.     fPercentWaste.i=format(PercentWaste.i,,2)
  841.     IntPFree.i=format(PercentFree.i,,0)
  842.     IntPUsed.i=format(PercentUsed.i,,0)
  843.     IntPWaste.i=format(PercentWaste.i,,0)
  844. end
  845.  
  846. if Visual\=1 then do
  847.     call SysCls
  848.     call SysCurPos 5,0
  849. end
  850.  
  851. if SkipEA=1 then
  852.     infochecked="        "
  853. else 
  854.     infochecked="and EA's"
  855.  
  856. rline.1.1="Drive "||TestDrive||" "||FormDriveSize||" bytes"
  857. rline.1.2=""
  858. rline.2.1=""
  859. rline.2.2=""
  860. rline.3.1="Total files                           "
  861. rline.3.2=": "||FormTotFiles 
  862. rline.4.1="Total size of files "||infochecked||"          "
  863. rline.4.2=": "||FormTotSize||" bytes" 
  864. rline.5.1=""
  865. rline.5.2=""
  866. rline.6.1="Current statistics using "||FileSystem.1||" :"
  867. rline.6.2=""
  868. rline.7.1=""
  869. rline.7.2=""
  870. rline.8.1="Allocation unit size                  "
  871. rline.8.2=": "||FormUnitSize.1||" bytes" 
  872. rline.9.1="Total space consumed by directories   "
  873. rline.9.2=": "||FormDirSpace.1||" bytes" 
  874. rline.10.1="Total wasted space for files "||infochecked||" "
  875. rline.10.2=": "||FormWasteSpace.1||" bytes" 
  876. rline.11.1=""
  877. rline.11.2=""
  878. rline.12.1="If it was being used with "||FileSystem.2||" :"
  879. rline.12.2=""
  880. rline.13.1=""
  881. rline.13.2=""
  882. rline.14.1="Allocation unit size                  "
  883. rline.14.2=": "||FormUnitSize.2||" bytes" 
  884. rline.15.1="Total space consumed by directories   "
  885. rline.15.2=": "||FormDirSpace.2||" bytes" 
  886. rline.16.1="Total wasted space for files "||infochecked||" "
  887. rline.16.2=": "||FormWasteSpace.2||" bytes" 
  888. rline.17=""
  889. if TotalDiff=0 then do
  890.     rline.18="Oddly enough, by using "||FileSystem.1||" instead of "||FileSystem.2||","
  891.     rline.19="you've neither saved nor lost any disk space on drive "||TestDrive||"."
  892. end
  893. else do
  894.     rline.18="By using "||FileSystem.1||" instead of "||FileSystem.2||", you've"
  895.     rline.19=Modifier||" "||FormTotalDiff||" bytes on drive "||TestDrive||"."
  896. end
  897.  
  898. if Visual\=1 | (Visual=1 & Outfile\='CON') then do
  899.     do i=1 to 16
  900.         rline.i=rline.i.1||rline.i.2
  901.     end
  902.     do i=1 to 19
  903.         call lineout OutFile,rline.i
  904.     end
  905.     if Visual\=1 & OutFile='CON' then do
  906.         say ""
  907.         say "Press any key to see the graph..."
  908.         junk=SysGetKey('noecho')
  909.         call SysCls
  910.         UseChar=d2c(219)
  911.         WasteChar=d2c(177)
  912.         FreeChar=d2c(176)
  913.         do i=1 to 2
  914.             NumUse.i=format(((PercentUsed.i/100)*50),,0)
  915.             NumWaste.i=format(((PercentWaste.i/100)*50),,0)
  916.             NumFree.i=format(((PercentFree.i/100)*50),,0)
  917.             if NumUse.i+NumWaste.i+NumFree.i <> 50 then 
  918.                 NumFree.i=50-(NumUse.i+NumWaste.i)
  919.         end
  920.         Graph.1=''
  921.         Graph.2=''
  922.         do i=1 to 2
  923.             do j=1 to NumUse.i
  924.                 Graph.i=Graph.i||UseChar
  925.             end
  926.         end
  927.         do i=1 to 2
  928.             do j=1 to NumWaste.i
  929.                 Graph.i=Graph.i||WasteChar
  930.             end
  931.         end
  932.         do i=1 to 2
  933.             do j=1 to NumFree.i
  934.                 Graph.i=Graph.i||FreeChar
  935.             end
  936.         end
  937.         GraphString.1='               '||Graph.1||crlf||'               '||,
  938.             Graph.1||crlf
  939.         GraphString.2='               '||Graph.2||crlf||'               '||,
  940.             Graph.2||crlf
  941.         tstring='Drive '||TestDrive||'    '||FormDriveSize||' bytes'
  942.         tspos=format(((80-(length(tstring)))/2),,0)
  943.         kstring=d2c(219)||' = used    '||d2c(177)||' = wasted    '||,
  944.             d2c(176)||' = free'
  945.         kspos=format(((80-(length(kstring)))/2),,0)
  946.         do i=1 to 2
  947.             pstring.i='With '||FileSystem.i||', '||fPercentUsed.i||'%'||' used, '||,
  948.                 fPercentWaste.i||'%'||' wasted, '||fPercentFree.i||'%'||' free.'
  949.             pspos.i=format(((80-(length(pstring.i)))/2),,0)
  950.         end
  951.         call SysCurPos 4,tspos
  952.         call charout ,tstring
  953.         call SysCurPos 6,kspos
  954.         call charout ,kstring
  955.         call SysCurPos 9,0
  956.         call charout ,GraphString.1
  957.         call SysCurPos 12,pspos.1
  958.         call charout ,pstring.1
  959.         call SysCurPos 15,0
  960.         call charout ,GraphString.2
  961.         call SysCurPos 18,pspos.2
  962.         call charout ,pstring.2
  963.         call charout ,crlf
  964.     end 
  965.     if Visual=1 then do
  966.         msg.0=1
  967.         msg.1='Results saved to '||OutFile||'.'
  968.         call VMsgBox 'Info',msg,1
  969.     end
  970. end
  971. else do
  972.     if Visual=1 then do
  973.         call VCloseWindow FileID
  974.         call VCloseWindow DirID
  975.         call VClearWindow MainID
  976.         dtitle='Drive '||TestDrive||' scan results'
  977.         call VSetTitle MainID,dtitle
  978.         PosY=TopText
  979.         do i=1 to 16
  980.             call VSay MainID,5,PosY,rline.i.1
  981.             call VSay MainID,StatsHalfTwo,PosY,rline.i.2
  982.             PosY=PosY-TextSpace
  983.         end
  984.         do i=17 to 19
  985.             call VSay MainID,5,PosY,rline.i
  986.             PosY=PosY-TextSpace
  987.         end
  988.         title='Comparison graphs'
  989.         gpos.left=GraphLeft
  990.         gpos.bottom=GraphBottom
  991.         gpos.right=GraphRight
  992.         gpos.top=GraphTop
  993.         GraphID=VOpenWindow(title,GraphColor,gpos)
  994.         call VForeColor GraphID,GraphTextColor
  995.         call VSetFont GraphID,'TIME',FontSize
  996.         hstring='Drive '||TestDrive||'    '||FormDriveSize||' bytes.'
  997.         call VSay GraphID,10,GTopText,hstring
  998.         ypos.1=TopKey
  999.         ypos.2=BottomKey
  1000.         call VForeColor GraphID,UsedColor
  1001.         call VDrawParms GraphID,0,0,5
  1002.         ux.1=120
  1003.         ux.2=160
  1004.         ux.3=160
  1005.         ux.4=120
  1006.         ux.5=ux.1
  1007.         uy.1=ypos.1
  1008.         uy.2=ypos.1
  1009.         uy.3=ypos.2
  1010.         uy.4=ypos.2
  1011.         uy.5=uy.1
  1012.         call VDraw GraphID,'POLYGON',ux,uy,4
  1013.         call VForeColor GraphID,WasteColor
  1014.         call VDrawParms GraphID,0,0,1
  1015.         wx.1=400
  1016.         wx.2=440
  1017.         wx.3=440
  1018.         wx.4=400
  1019.         wx.5=wx.1
  1020.         wy.1=ypos.1
  1021.         wy.2=ypos.1
  1022.         wy.3=ypos.2
  1023.         wy.4=ypos.2
  1024.         wy.5=wy.1
  1025.         call VDraw GraphID,'POLYGON',wx,wy,4
  1026.         call VForeColor GraphID,FreeColor
  1027.         call VDrawParms GraphID,0,0,2
  1028.         fx.1=680
  1029.         fx.2=720
  1030.         fx.3=720
  1031.         fx.4=680
  1032.         fx.5=fx.1
  1033.         fy.1=ypos.1
  1034.         fy.2=ypos.1
  1035.         fy.3=ypos.2
  1036.         fy.4=ypos.2
  1037.         fy.5=fy.1
  1038.         call VDraw GraphID,'POLYGON',fx,fy,4
  1039.         call VForeColor GraphID,GraphTextColor
  1040.         call VDraw GraphID,'LINE',ux,uy,5
  1041.         call VDraw GraphID,'LINE',wx,wy,5
  1042.         call VDraw GraphID,'LINE',fx,fy,5
  1043.         
  1044.         ustring='= Used'
  1045.         wstring='= Wasted'
  1046.         fstring='= Free'
  1047.         call VSay GraphID,170,KeyName,ustring
  1048.         call VSay GraphID,450,KeyName,wstring
  1049.         call VSay GraphID,730,KeyName,fstring
  1050.         ypos.1=GraphTopOne
  1051.         ypos.2=GraphTopTwo
  1052.         do i=1 to 2
  1053.             UsedLength.i=format(((PercentUsed.i/100)*700),,0)
  1054.             WasteLength.i=format(((PercentWaste.i/100)*700),,0)
  1055.             FreeLength.i=format(((PercentFree.i/100)*700),,0)
  1056.         end
  1057.  
  1058.         ux1.1=150
  1059.         ux1.2=150+UsedLength.1
  1060.         ux1.3=ux1.2
  1061.         ux1.4=150
  1062.         uy1.1=ypos.1
  1063.         uy1.2=ypos.1
  1064.         uy1.3=ypos.1-150
  1065.         uy1.4=ypos.1-150
  1066.         wx1.1=ux1.2+1
  1067.         wx1.2=wx1.1+WasteLength.1
  1068.         wx1.3=wx1.2
  1069.         wx1.4=wx1.1
  1070.         wy1.1=ypos.1
  1071.         wy1.2=ypos.1
  1072.         wy1.3=ypos.1-150
  1073.         wy1.4=ypos.1-150
  1074.         fx1.1=wx1.2+1
  1075.         fx1.2=fx1.1+FreeLength.1
  1076.         fx1.3=fx1.2
  1077.         fx1.4=fx1.1
  1078.         fy1.1=ypos.1
  1079.         fy1.2=ypos.1
  1080.         fy1.3=ypos.1-150
  1081.         fy1.4=ypos.1-150
  1082.  
  1083.         ux2.1=150
  1084.         ux2.2=150+UsedLength.2
  1085.         ux2.3=ux2.2
  1086.         ux2.4=150
  1087.         uy2.1=ypos.2
  1088.         uy2.2=ypos.2
  1089.         uy2.3=ypos.2-150
  1090.         uy2.4=ypos.2-150
  1091.         wx2.1=ux2.2+1
  1092.         wx2.2=wx2.1+WasteLength.2
  1093.         wx2.3=wx2.2
  1094.         wx2.4=wx2.1
  1095.         wy2.1=ypos.2
  1096.         wy2.2=ypos.2
  1097.         wy2.3=ypos.2-150
  1098.         wy2.4=ypos.2-150
  1099.         fx2.1=wx2.2+1
  1100.         fx2.2=fx2.1+FreeLength.2
  1101.         fx2.3=fx2.2
  1102.         fx2.4=fx2.1
  1103.         fy2.1=ypos.2
  1104.         fy2.2=ypos.2
  1105.         fy2.3=ypos.2-150
  1106.         fy2.4=ypos.2-150
  1107.  
  1108.         call VForeColor GraphID,UsedColor
  1109.         call VDrawParms GraphID,0,0,5
  1110.         call VDraw GraphID,'POLYGON',ux1,uy1,4
  1111.         call VDraw GraphID,'POLYGON',ux2,uy2,4
  1112.         call VForeColor GraphID,WasteColor
  1113.         call VDrawParms GraphID,0,0,1
  1114.         call VDraw GraphID,'POLYGON',wx1,wy1,4
  1115.         call VDraw GraphID,'POLYGON',wx2,wy2,4
  1116.         call VForeColor GraphID,FreeColor
  1117.         call VDrawParms GraphID,0,0,2
  1118.         call VDraw GraphID,'POLYGON',fx1,fy1,4
  1119.         call VDraw GraphID,'POLYGON',fx2,fy2,4
  1120.     
  1121.         bx1.1=149
  1122.         bx1.2=852
  1123.         bx1.3=bx1.2
  1124.         bx1.4=bx1.1
  1125.         bx1.5=bx1.1
  1126.         by1.1=ypos.1+1
  1127.         by1.2=ypos.1+1
  1128.         by1.3=ypos.1-151
  1129.         by1.4=ypos.1-151
  1130.         by1.5=by1.1
  1131.         bx2.1=149
  1132.         bx2.2=852
  1133.         bx2.3=bx2.2
  1134.         bx2.4=bx2.1
  1135.         bx2.5=bx2.1
  1136.         by2.1=ypos.2+1
  1137.         by2.2=ypos.2+1
  1138.         by2.3=ypos.2-151
  1139.         by2.4=ypos.2-151
  1140.         by2.5=by2.1
  1141.  
  1142.         call VForeColor GraphID,GraphTextColor
  1143.         call VDrawParms GraphID,0,0,0
  1144.         call VDraw GraphID,'LINE',bx1,by1,5
  1145.         call VDraw GraphID,'LINE',bx2,by2,5
  1146.  
  1147.         do i=1 to 2
  1148.             pstring.i='With '||FileSystem.i||', '||fPercentUsed.i||'%'||,
  1149.                 ' used, '||fPercentWaste.i||'%'||' wasted, '||fPercentFree.i||,
  1150.             '% free.'
  1151.         end
  1152.         call VForeColor GraphID,GraphTextColor
  1153.         call VSay GraphID,100,GraphTextOne,pstring.1
  1154.         call VSay GraphID,100,GraphTextTwo,pstring.2
  1155.         call VDialogPos 80,50
  1156.         do until confirm=1
  1157.             ExitChoice.0=2
  1158.             ExitChoice.1='Exit DriveCheck'
  1159.             ExitChoice.2='Log results to file, then exit DriveCheck'
  1160.             ExitChoice.vstring=ExitChoice.1
  1161.             call VRadioBox 'Exiting DriveCheck',ExitChoice,1
  1162.             choice=ExitChoice.vstring
  1163.             if choice=ExitChoice.1 then confirm=1
  1164.             else do 
  1165.                 click=VFileBox('File to save results to','',log)
  1166.                 if click='CANCEL' then confirm=0 
  1167.                 else do
  1168.                     logfile=log.vstring
  1169.                     check=lineout(logfile,'check')
  1170.                     if check=1 then do
  1171.                         msg.0=1
  1172.                         msg.1='Invalid filename chosen.'
  1173.                         call VMsgBox 'Invalid Filename',msg,1
  1174.                         confirm=0
  1175.                     end
  1176.                     else do    
  1177.                         call stream logfile,'c','close'
  1178.                         call SysFileDelete logfile
  1179.                         msg.0=1
  1180.                         msg.1='Save results to '||logfile||'?'
  1181.                         ans=VMsgBox('Confirmation',msg,3)
  1182.                         if ans='OK' then do
  1183.                             confirm=1
  1184.                             do i=1 to 16
  1185.                                 rline.i=rline.i.1||rline.i.2
  1186.                             end
  1187.                             do i=1 to 19
  1188.                                 call lineout logfile,rline.i
  1189.                             end
  1190.                         end
  1191.                         else confirm=0
  1192.                     end
  1193.                 end
  1194.             end    
  1195.         end    
  1196.     end
  1197. end
  1198. call directory CurrDir
  1199. if Visual\=1 & OutFile\='CON' then say 'Results saved to '||Outfile||'.'
  1200. if Visual=1 then call VExit
  1201. exit
  1202.  
  1203. SYNTAX:
  1204. prob='SYNTAX'
  1205. proba=1
  1206. ERROR:
  1207. if proba\=1 then do
  1208.     prob='ERROR'
  1209.     proba=1
  1210. end
  1211. FAILURE:
  1212. if proba\=1 then do
  1213.     prob='FAILURE'
  1214.     proba=1
  1215. end
  1216. HALT:
  1217. if proba\=1 then prob='HALT'
  1218.  
  1219. say ''
  1220. say ''
  1221. say 'Problem of type '||prob||' while program was on line '||sigl||'.'
  1222. say '"'Sourceline(sigl)'"'
  1223. call directory CurrDir
  1224. if Visual=1 then call VExit
  1225. exit
  1226.  
  1227. Usage:
  1228. call SysCls
  1229. call SysCurPos 5,0
  1230. say "DriveCheck v"||DCVer||" REXX disk space waste scanner, written by:"
  1231. say ""
  1232. say "Mike Ruskai <thanny@ibm.net>"
  1233. say ""
  1234. say "Usage: DRIVECHK.CMD [/T] [<drive letter>: [/S|/N] [/O:<filename>|/C]]"
  1235. say ""
  1236. say "/T               - Run in text mode (no graphical interface)"
  1237. say "<drive letter>:  - Drive to scan"
  1238. say "/S               - Skip extended attributes checking"
  1239. say "/N               - Do not skip extended attributes checking"
  1240. say "/O:<filename>    - Write output to <filename>"
  1241. say "/C               - Do not direct output to a file"
  1242. say ""
  1243. say "Example:"
  1244. say ""
  1245. say "DRIVECHK C: /S /O:scan.log"
  1246. say ""
  1247. say " - Scans drive C:, skips EA's, writes output to 'scan.log'"
  1248. say ""
  1249. say "Run DRIVECHK.CMD with no parameters to be prompted for input."
  1250. say "Use of the /T parameter alone results in text-only prompting."
  1251. say ""
  1252. exit
  1253. /******************** Begin TallyFiles Procedure **********************/
  1254. /* Procedure to determine total size and waste of all files in a      */
  1255. /* given directory, for both FAT and HPFS file systems.  The list of  */
  1256. /* files is obtained using SysFileTree.  For each file, it's total    */
  1257. /* size and the size of its EA's (unless skipped) are tallied for the */
  1258. /* file size total, and the waste of the file and it's EA's is added  */
  1259. /* to the waste total.  Calculations are performed by the SlackSpace  */
  1260. /* procedure, for both FAT and HPFS file systems.                     */
  1261.  
  1262. TallyFiles: Procedure expose Fnode.1 Fnode.2 SkipEA UShell AUnit.1 AUnit.2 Visual FileID orexx
  1263.  
  1264. ClrStr='                               '
  1265. ClrStr=ClrStr||ClrStr||' '
  1266. TotSize=0
  1267. TotWaste.1=0
  1268. TotWaste.2=0
  1269. TotAlloc.1=0
  1270. TotAlloc.2=0
  1271. arg Dir
  1272. call directory Dir
  1273. call SysFileTree '*','files.','F'
  1274. if Visual\=1 then do
  1275.     call SysCurPos 14,0
  1276.     call charout ,'Working on file: '
  1277. end
  1278. do i=1 to files.0
  1279.     if SkipEA=1 then do
  1280.         CurFile=filespec('name',(substr(files.i,38)))
  1281.         if length(CurFile)>63 then
  1282.             dCurFile=substr(CurFile,1,62)||'>'
  1283.         else dCurFile=CurFile
  1284.         if Visual=1 then do
  1285.             call VClearWindow FileID
  1286.             str=CurFile
  1287.             call VSay FileID,5,500,str
  1288.         end
  1289.         else do
  1290.             call SysCurPos 14,17
  1291.             say ClrStr
  1292.             call SysCurPos 14,17
  1293.             call charout ,dCurFile        
  1294.         end
  1295.         FSize=word(files.i,3)
  1296.         TotSize=TotSize+FSize
  1297.         Waste=SlackSpace(Fsize)
  1298.         TotWaste.1=TotWaste.1+word(Waste,1)+Fnode.1
  1299.         TotWaste.2=TotWaste.2+word(Waste,2)+Fnode.2
  1300.     end
  1301.     else do
  1302.         file=substr(files.i,38)
  1303.         p1=right(d2x(random(65535)),4,'0')
  1304.         p2=right(d2x(random(65535)),4,'0')
  1305.         tfile='\'||p1||p2||'.TMP'
  1306.         if UShell='4OS2' then do
  1307.             signal off error
  1308.             '*@dir/a/knm '||'"'file'"'||'>'||tfile
  1309.             signal on error
  1310.             CurFile=filespec('name',file)
  1311.             if length(CurFile)>63 then
  1312.                 dCurFile=substr(CurFile,1,62)||'>'
  1313.             else dCurFile=CurFile
  1314.             if Visual=1 then do
  1315.                 call VClearWindow FileID
  1316.                 str=CurFile
  1317.                 call VSay FileID,5,500,str
  1318.             end
  1319.             else do 
  1320.                 call SysCurPos 14,17
  1321.                 say ClrStr
  1322.                 call SysCurPos 14,17
  1323.                 call charout ,dCurFile        
  1324.             end
  1325.             filestring=linein(tfile)
  1326.             UFEASize=word(filestring,4)
  1327.             UFFSize=word(filestring,3)
  1328.             EACommaPos=pos(',',UFEASize)
  1329.             if EACommaPos\=0 then
  1330.                 EASize=delstr(UFEASize,EACommaPos,1)
  1331.             else EASize=UFEASize
  1332.             FCommaPos=pos(',',UFFSize)
  1333.             if FCommaPos\=0 then do until FCommaPos=0
  1334.                 UFFSize=delstr(UFFSize,FCommaPos,1)
  1335.                 FCommaPos=pos(',',UFFSize)
  1336.             end 
  1337.             FSize=UFFSize
  1338.         end
  1339.         else do
  1340.             '@dir/a/n '||'"'file'"'||'>'||tfile
  1341.             CurFile=filespec('name',file)
  1342.             if length(CurFile)>63 then
  1343.                 dCurFile=substr(CurFile,1,62)||'>'
  1344.             else dCurFile=CurFile
  1345.             if Visual=1 then do
  1346.                 call VClearWindow FileID
  1347.                 str=CurFile
  1348.                 call VSay FileID,5,500,str
  1349.             end
  1350.             else do
  1351.                 call SysCurPos 14,17
  1352.                 say ClrStr
  1353.                 call SysCurPos 14,17
  1354.                 call charout ,dCurFile        
  1355.             end
  1356.             do 5
  1357.                 scrap=linein(tfile)
  1358.             end
  1359.             filestring=linein(tfile)
  1360.         EASize=word(filestring,4)
  1361.         FSize=word(filestring,3)
  1362.         end
  1363.         TotSize=TotSize+FSize+EASize
  1364.         FWaste=SlackSpace(FSize)
  1365.         FWaste.1=word(FWaste,1)
  1366.         FWaste.2=word(FWaste,2)
  1367.         if EASize=0 then do
  1368.             TotWaste.1=TotWaste.1+FWaste.1+Fnode.1
  1369.             TotWaste.2=TotWaste.2+FWaste.2+Fnode.2
  1370.         end
  1371.         else do
  1372.             EAWaste=SlackSpace(EASize)
  1373.             EAWaste.1=word(EAWaste,1)
  1374.             EAWaste.2=word(EAWaste,2)
  1375.             TotWaste.1=TotWaste.1+FWaste.1+EAWaste.1
  1376.             TotWaste.2=TotWaste.2+FWaste.2+EAWaste.2
  1377.         end
  1378.         call stream tfile,'c','close'
  1379.         call SysFileDelete tfile
  1380.     end
  1381.     if orexx=1 then call SysSleep 0.005
  1382. end
  1383. return TotSize TotWaste.1 TotWaste.2 files.0
  1384. /******************** End TallyFiles Procedure ************************/
  1385.  
  1386. /******************** Begin SlackSpace Procddure **********************/
  1387. /* Procedure to determine the wasted space of the given file size.    */
  1388. /* This procedure receives the file size and allocation unit size     */
  1389. /* from the main program.  It divides the file size by the size of    */
  1390. /* the allocation unit, then multiplies the integer portion the       */
  1391. /* result to obtain the space occupied only by completely used        */
  1392. /* allocation units.  The difference between this and the size of the */
  1393. /* file is then subtracted from the size of the allocation unit which */
  1394. /* results in the amount of wasted space, in bytes.  Of course, if    */
  1395. /* there is no partial allocation unit usage, there is no wasted      */
  1396. /* space, and 0 is returned in such a case.                           */
  1397.  
  1398. SlackSpace: Procedure expose AUnit.1 AUnit.2 
  1399.  
  1400. arg FileSize
  1401. do i=1 to 2
  1402.     IntUnit.i=FileSize%AUnit.i
  1403.     FullUnits.i=IntUnit.i*AUnit.i
  1404.     Diff.i=FileSize-FullUnits.i
  1405.     if Diff.i=0 then do
  1406.         Waste.i=0
  1407.         AllocUnits.i=IntUnit.i
  1408.     end
  1409.     else do
  1410.         Waste.i=AUnit.i-Diff.i
  1411.         AllocUnits.i=IntUnit.i+1
  1412.     end
  1413.     TotAlloc.i=AllocUnits.i*AUnit.i
  1414.     if orexx=1 then call SysSleep 0.005
  1415. end
  1416. return Waste.1 Waste.2
  1417. /******************** End SlackSpace Procedure ************************/
  1418.  
  1419. /******************** Begin ProcDir Procedure *************************/
  1420. /* Procedure to get all information about a specific directory, which */
  1421. /* includes total file and EA size and wasted space (for both FAT and */
  1422. /* HPFS).                                                             */
  1423.  
  1424. ProcDir: Procedure expose FNode.1 FNode.2 AUnit.1 AUnit.2 UShell SkipEA Visual FileID orexx
  1425.  
  1426. arg DirName
  1427. TSize=TallyFiles(DirName)
  1428. FSize=word(TSize,1)
  1429. Waste.1=word(TSize,2)
  1430. Waste.2=word(TSize,3)
  1431. NumFiles=word(TSize,4)
  1432. return Waste.1 Waste.2 FSize NumFiles
  1433. /******************** End ProcDir Procedure ***************************/
  1434.  
  1435. /******************** Begin TallyDirEA Procedure **********************/
  1436. /* Procedure to tally the extended attributes of a given directory,   */
  1437. /* which is done regardless of the SkipEA status, since it doesn't    */
  1438. /* really take that long.  The parent of the given directory is       */
  1439. /* changed to, so we can do a DIR listing of all directories, and     */
  1440. /* parse the information about the specific one we want from the list */
  1441. /* returned.  There seems to be no way to list only a specific        */
  1442. /* directory in either CMD.EXE or 4OS2.EXE.  Once the EA size for the */
  1443. /* directory is found, the total actual space taken up for each       */
  1444. /* allocation unit is calculated, and returned.                       */
  1445.  
  1446. TallyDirEA: Procedure expose AUnit.1 AUnit.2 UShell
  1447.  
  1448. arg DirName
  1449. tDirName=reverse(DirName)
  1450. BSPos=pos('\',tDirName)
  1451. BDName=translate(reverse(substr(tDirName,1,(BSPos-1))))
  1452. call directory DirName||'\..'
  1453. p1=right(d2x(random(65535)),4,'0')
  1454. p2=right(d2x(random(65535)),4,'0')
  1455. tfile='\'||p1||p2||'.TMP'
  1456. if UShell='4OS2' then do
  1457.     signal off error
  1458.     '@*dir/n/m/k/h/ad > '||tfile
  1459.     signal on error
  1460.     do until found=1
  1461.         dirstring=linein(tfile)
  1462.         if translate(subword(dirstring,5))=BDName then do
  1463.             UFEASize=word(dirstring,4)           
  1464.             EACommaPos=pos(',',UFEASize)
  1465.             if EACommaPos\=0 then
  1466.                 EASize=delstr(UFEASize,EACommaPos,1)
  1467.             else EASize=UFEASize
  1468.             found=1
  1469.         end
  1470.         else found=0
  1471.     end
  1472. end
  1473. else do
  1474.     '@dir/n/ad > '||tfile
  1475.     do 5
  1476.         scrap=linein(tfile)
  1477.     end
  1478.     do until found=1
  1479.         dirstring=linein(tfile)
  1480.         if translate(subword(dirstring,5))=BDName then do
  1481.             EASize=word(dirstring,4)
  1482.             found=1
  1483.         end
  1484.         else found=0
  1485.     end
  1486. end
  1487. call stream tfile,'c','close'
  1488. call SysFileDelete tfile
  1489. DSData=SlackSpace(EASize)
  1490. DirEATot.1=EASize+word(DSData,1)
  1491. DirEATot.2=EASize+word(DSData,2)
  1492. return DirEATot.1 DirEATot.2
  1493. /******************** End TallyDirEA Procedure ************************/
  1494.  
  1495. /******************** Begin CoDel Procedure ***************************/
  1496. /* Procedure to take a long decimal number, and deliminate it with a  */
  1497. /* comma for each group of three digits, starting from the end of the */
  1498. /* number.  First you reverse the string.  Then you take the first    */
  1499. /* three characters of the reversed string (i.e. last three           */
  1500. /* characters of the original string), writing the remaining          */
  1501. /* characters back to the variable.  The three characters are         */
  1502. /* appended to the final string with a comma at the end, and the      */
  1503. /* process is repeated until there are three or less characters left  */
  1504. /* in the reversed string variable.  The final write of the formatted */
  1505. /* string appends the remaining digits.  The string is then reversed  */
  1506. /* again (putting it back to normal), which results in a readable     */
  1507. /* number:                                                            */
  1508. /*                                                                    */
  1509. /*  2484693813       - Original string                                */
  1510. /*  3183964842       - Reversed                                       */
  1511. /*  318,             - Three chars and comma appended to final string */
  1512. /*  318,396,         - Next three and a comma                         */
  1513. /*  318,396,484,     - Next three and a comma                         */
  1514. /*  318,396,484,2    - Last char(s), three or less, no comma          */
  1515. /*  2,484,693,813    - Reversed back to normal                        */
  1516.  
  1517. CoDel: Procedure
  1518.  
  1519. arg RNum
  1520. rRNum=reverse(RNum)
  1521. FNum=''
  1522. do while length(rRNum)>3
  1523.     parse var rRNum TriDig +3 rRNum
  1524.     FNum=FNum||TriDig||','
  1525. end
  1526. FNum=reverse(FNum||rRNum)
  1527. return FNum
  1528. /******************** End CoDel Procedure *****************************/
  1529.  
  1530. /******************** Begin ColorCheck Procedure **********************/
  1531. /* This procedure simply verifies that the colors read in from the    */
  1532. /* INI file (if present) are valid or not.                            */
  1533.  
  1534. ColorCheck: Procedure
  1535.  
  1536. arg color
  1537. if color='BLACK' then rv=1
  1538. else if color='WHITE' then rv=1
  1539. else if color='RED' then rv=1
  1540. else if color='GREEN' then rv=1
  1541. else if color='BLUE' then rv=1
  1542. else if color='CYAN' then rv=1
  1543. else if color='YELLOW' then rv=1
  1544. else if color='PINK' then rv=1
  1545. else rv=0
  1546. return rv
  1547. /******************** End ColorCheck Procedure ************************/
  1548.  
  1549. /******************** Begin ResCheck Procedure ************************/
  1550. /* Simply checks to see if a resolution given in the INI file is one  */
  1551. /* which we know how to handle.                                       */
  1552.  
  1553. ResCheck: Procedure
  1554.  
  1555. arg res
  1556. if res='640X480' then rv=1
  1557. else if res='800X600' then rv=1
  1558. else if res='1024X768' then rv=1
  1559. else if res='1280X1024' then rv=1
  1560. else if res='1600X1200' then rv=1
  1561. else rv=0
  1562. return rv
  1563. /******************** End ResCheck Procedure **************************/
  1564.