[Back to DRIVES SWAG index] [Back to Main SWAG index] [Original]

    program FREE;  { show free disk space and other info }
    {$M 32000,0,100000}

    {$IFDEF Windows}
      This program is intended for DOS real mode only!
    {$ELSE}
      {$IFDEF DPMI}
        Compile for real mode so program does not need RTM.EXE and DPMI16BI.OVL!
      {$ENDIF}
    {$ENDIF}

       {-------------------------------------------------------------------------}
       {                                                                         }
       {                              FREE.PAS                                   }
       {                              ========                                   }
       {     Display drive information and handle phantom floppy drives so       }
       {     that you don't get the annoying 'insert disk in drive' message.     }
       {     That means when a non-active phantom floppy drive letter is         }
       {     listed on the command line, list it's mapped drive and show the     }
       {     info for the mapped drive, like this:                               }
       {                                                                         }
       {             Free A:   ----------- - same drive as B                     }
       {             Free B:             0 - drive not ready                     }
       {                                                                         }
       {     See the program Usage display (FREE /?) for more information.       }
       {                                                                         }
       {-------------------------------------------------------------------------}
       {           This program uses the Object Professional library by          }
       {                          TurboPower Software.                           }
       {-------------------------------------------------------------------------}
       {   (c) 1995 by Ray Bernard Consulting and Design. All Rights Reserved.   }
       {   Portions (c) 1995 by TurboPower Software. All Rights Reserved.        }
       {-------------------------------------------------------------------------}

       {-------------------------------------------------------------------------}
       {  ABOUT THIS PROGRAM                                                     }
       {  ==================                                                     }
       {  We developed this program to show drive information because it seemed  }
       {  like we were always adding new drives to our computers, then changing  }
       {  around the drive contents to optimize their usage. Most of the 1 gig   }
       {  drives are partitioned into 4 drives for maximum utilization (to make  }
       {  16K sectors instead of 32K sectors). Whenever we would rearrange       }
       {  drive contents, it was helpful to have a utility that would identify   }
       {  all of a computers local and networked drives, and display the drive   }
       {  volume label and type of drive.                                        }
       {                                                                         }
       {  Now that most of the kinks are worked out of this program, it seemed   }
       {  fitting to upload the source code to TurboPower's BBS and CIS forum,   }
       {  in case others would find it handy.                                    }
       {                                                                         }
       {  This program is provided "AS-IS" without any warranty. Although it is  }
       {  copyrighted, free use may be made of the source code by any registered }
       {  TurboPower software customers. Free use may be made of the compiled    }
       {  version regardless of TurboPower customer status.                      }
       {                                                                         }
       {  -Ray Bernard                                                           }
       {   Ray Bernard Consulting and Design      CIS: [73354,3325]              }
       {   June 17, 995                                                          }
       {-------------------------------------------------------------------------}

    Uses
      DOS,
      OpDOS,
      OpCrt,
      OpString,
      OpInline;

    type
      TPhantomRec = record
                      DrvLtr,
                      MapDrvLtr : Char;
                    end;

    var
      DriveList      : String[26];  { drive letters extracted from command line }
      HighDriveSpace,
      LowDriveSpace  : LongInt;     { to hold LOW and HIGH options space values }
      ReportOptions  : Word;        { set per command line options }
      PhantomList    : array['A'..'Z'] of TPhantomRec; { phantom drive global list }

    const
     { Report Options for ShowFreeSpaceAllDrives }

      ShowAtOrAbove   = $00000001;   { /H }
      ShowAtOrBelow   = $00000002;   { /L }
      ShowAndPause    = $00000004;   { /P }
      ShowAllDrives   = $00000008;   { /A }
      ShowSize        = $00000010;   { /C }
      ShowType        = $00000020;   { /T }
      ShowVolumeLabel = $00000040;   { /V }
      ShowFloppies    = $00000080;   { /F }

      MsPerSec       = 1000;
      Kbyte          = 1024;
      Megabyte       = 1024*Kbyte;
      Gigabyte       = 1024*Megabyte;
      FreeSpacePad   = 11;   { pad free space number string to 11 spaces }

     { global declarations }
      DriveLetterSet     : set of Char = ['A'..'Z'];  { for parameter checking }
      CommandDelimiters  : set of char = ['-','/'];   { for parameter checking }

      PauseDelaySecs     : Word = 5;  { default seconds to pause after display }
      Debug              : Boolean = True;

      DosVer300 = $0300; {for DOS 3.00}
      DosVer320 = $0314; {for DOS 3.20, $14 = 20}

    procedure ShowUsageAndHalt;
    {-Show the usage information for this program }
    begin
      HighVideo;
      Writeln('FREE.EXE - Display drive free space and other information.');
      LowVideo;
      Writeln('(c) 1995 by Ray Bernard Consulting and Design, CompuServe: 73354,3325.');
      Writeln('Portions (c) 1987-1995 by TurboPower Software. All Rights Reserved.');
      Writeln('FREE.EXE is "freeware", distributed "as is" and without warranty.');
      Writeln;
      HighVideo;
      Write('Usage: ');
      LowVideo;
      Writeln('FREE [Drives] [Options]');
      Writeln;
      HighVideo;
      Write('Drives: ');
      LowVideo;
      Writeln('One or more drive letters, with or without spaces');
      Writeln('separating them. If no drives are listed the default drive is assumed.');
      Writeln;
      HighVideo;
      Write('Options: ');
      LowVideo;
      Writeln('One or more options, separated by spaces. You may');
      Writeln('also use the first letter of the option, such as /A for /ALL.');
      Writeln('/ALL       show all drives (A and B)');
      Writeln('/FLOPPY    show all drives including A and B');
      Writeln('/HIGH n    all drives with n or more free space');
      Writeln('/LOW n     all drives with n or less free space');
      Writeln('/PAUSE     pause 5 seconds after display or until key pressed');
      Writeln('/PAUSE n   pause n seconds after the display or until key pressed');
      Writeln('/SIZE      drive size (formatted capacity)');
      Writeln('/TYPE      type of drive');
      Writeln('/VOLUME    show volume label');
      Writeln;
      Write('Press a key to continue . . .');
      if ReadKey <> #0 then
       {do nothing} ;
      ClrScr;
      Writeln('FREE.EXE - Usage information, page 2.');
      Writeln;
      Writeln('High and Low free space amounts can be specified in bytes, kbytes, ');
      Writeln('megabytes or gigabytes using (K, M or G), with or without commas to separate');
      Writeln('thousands. Example: 52,428,800 or 52428800 or 50M for fifty megabytes.');
      Writeln;
      Writeln('EXAMPLE PROGRAM OUTPUT:');
      Writeln;
      Writeln('C:>FREE /f /t /v /s');
      Writeln('Free A:             0 (Size 0.0MB) - drive not ready');
      Writeln('Free B:             0 (Size 0.0MB) - drive not ready');
      Writeln('Free C:    48,283,648 (Size 515MB) - local hard drive  IDE#1_V1');
      Writeln('Free D:    47,218,688 (Size 251MB) - local hard drive  IDE#2_V1');
      Writeln('Free E:   162,906,112 (Size 519MB) - local hard drive  SCSI#1_V1');
      Writeln('Free F:    72,351,744 (Size 257MB) - local hard drive  IDE#1_V3');
      Writeln('Free G:    34,570,240 (Size 257MB) - local hard drive  IDE#1_V4');
      Writeln('Free H:    35,274,752 (Size 251MB) - local hard drive  IDE#2_V2');
      Writeln('Free K:   203,807,616 (Size   2GB) - remote or network drive  AT_SERV_C');
      Writeln('Free O:   ----------- - same drive as B');
      Writeln('Free N:    34,570,240 (Size 257MB) - logical SUBST or ASSIGN on G  IDE#1_V4');
      Writeln('Free R:             0 (Size 127MB) - CD-ROM Drive      MFCDISC');
      Writeln;
      Halt;
    end;

    function IsDriveLocal(Drive : Byte) : Boolean;
    { -Returns TRUE if drive is local.
       Drive is the drive number (0 for default, 1 for A:, 2 for B: ...).
       NOTE: If DOS 3 or greater is not loaded, it is assumed that the Drive is
       local (since DOS has no standard way of knowing under DOS 2).
       IsDriveLocal is taken from SHARE.PAS, a unit supplied with TurboPower's
       B-Tree Filer. }
    var
      Regs : Registers;
    begin
      if OpDos.DosVersion >= DosVer300 then   {DOS 3 or greater required}
        begin
          with Regs do
            begin
              AX := $4409;
              BL := Drive;
              MsDos(Regs);
              if Odd(Flags) then
                IsDriveLocal := True  {if error, then assume drive is local}
              else
                {the drive is local if bit 12 of DX is clear}
                IsDriveLocal := not FlagIsSet(DX,$1000);
            end;
        end
      else
        IsDriveLocal := True;     {assume it's local for DOS < 3}
    end;

    function DrvNumToLtr(DriveNum : Byte) : Char;
    {-Return Drive Letter for 1-based Drive Number (A=1, B=2, etc.)}
    begin
      DrvNumToLtr := Chr(DriveNum+64);
    end;

    function DrvLtrToNum(DriveLetter : Char) : Byte;
    {-Return 1-based Drive Number (A=1, B=2, etc.) for DriveLetter}
    begin
      DrvLtrToNum := Ord(Upcase(DriveLetter))-64;
    end;

    function IsDrivePhantom(DriveLetter : Char; var MappedTo : Char) : Boolean;
    {-Return True if Phantom drive and pass back original drive mapped to. }
    { Will recognize floppy drives drives reassigned using DRIVER.SYS.     }
    var
      Regs : Registers;
      IsPhantom : Boolean;
      DriveNum : Byte;
    begin
      IsPhantom := False;
      DriveNum := DrvLtrToNum(DriveLetter);
      if OpDos.DosVersion > DosVer320 then
        begin  {DOS 3.2 or greater required}
          with Regs do
            begin
              AX := $440E;
              BL := DriveNum;
              MsDos(Regs);
              if Odd(Flags) then
                begin
                  IsPhantom := False;  {if error, then assume drive not phantom }
                end
              else
                begin
                  if AL = 0 then       {the drive is not phantom drive if AL = 0}
                    IsPhantom := False
                  else
                    begin
                      IsPhantom := (AL <> DriveNum);
                      if IsPhantom then
                        MappedTo := DrvNumToLtr(AL);
                    end;
                end;
            end;
        end;
      IsDrivePhantom := IsPhantom;
    end; { IsDrivePhantom }

    function IsListedAsPhantom(DriveLetter : Char) : Boolean;
    {-Refer to this program's global PhantomList variable }
    begin
      IsListedAsPhantom := PhantomList[DriveLetter].DrvLtr = DriveLetter;
    end;

    procedure RestoreOutputRedirection;
    {-Return Write and Writeln to Standard I/O to allow }
    { redirection of program output to file or printer  }
    begin
      { undo OpCrt's assignment of Output to CRT }
      Close(Output);
      Assign(Output,'');
      Rewrite(Output);
    end;

    function NumFloppies : Byte;
    {-Return the number of floppy drives installed per DOS "List of Lists" }
    var
      Equipment : Byte;
    begin
      Equipment := mem[$0040:$0010];
      if (equipment and $0001) = 1 then
        NumFloppies := ((Equipment shr 6) and $0003)+1
      else
        NumFloppies := 0;
    end;

    procedure HaltWithMessage(Message : String);
    {-Display Message and halt }
    begin
      Writeln(Message);
      Halt;
    end;

    function InsertCommas(S : String) : String;
    {-Add commas to string for thousands. Work from the end  }
    { of the string exit on the first space encountered, to  }
    { be able to handle strings like: 'TOTAL: 1,000'.        }
    var
      I : Word;
      Len : Word;
    begin
      Len := Length(S);
      I := Len;
      while I > 1 do begin
        if (Len+1-I) mod 3 = 0 then
          if S[I-1] = ' ' then
            Break
          else
            insert(',', S, I);
        dec(I);
      end;
      InsertCommas := S;
    end;

    procedure GetAndSavePhantomInfo(DriveLetter : Char);
    {-If DriveLetter is a Phantom drive, set data in PhantomList }
    var
      MapCh : Char;
    begin
      if IsDrivePhantom(DriveLetter,MapCh) then
        with PhantomList[DriveLetter] do
          begin
            DrvLtr := DriveLetter;
            MapDrvLtr := MapCh;
          end;
    end;

    function DiskTypeString(DriveLetter : Char) : String;
    {-Return the disk class information as a string with leading space & dash. }
    { Checks the global variable PhantomList for phantom drive info, and exit  }
    { for phantom drive without calling GetDiskClass to avoid disk hit.        }
    var
      DiskType   : DiskClass;
      DriveNum   : Byte;
      SubDriveCh : Char;
      DTStr      : String;
    begin
      DriveNum := DrvLtrToNum(DriveLetter);
      if IsListedAsPhantom(DriveLetter) then
        begin
          DiskTypeString := ' - same drive as '+PhantomList[DriveLetter].MapDrvLtr;
          Exit;
        end;
      DiskType := GetDiskClass(DriveLetter,SubDriveCh);
      case DiskType of
        Floppy360    : DTStr := ' - 360KB,  5.25" diskette';
        Floppy720    : DTStr := ' - 720KB,  3.50" diskette';
        Floppy12     : DTStr := ' - 1.2MB,  5.25" diskette';
        Floppy144    : DTStr := ' - 1.44MB, 3.50" diskette';
        OtherFloppy  : DTStr := ' - unlised diskette type';
        Bernoulli    : DTStr := ' - Bernouli drive';
        HardDisk     : DTStr := ' - local hard drive';
        RamDisk      : DTStr := ' - RAM drive';
        SubstDrive   : DTStr := ' - logical SUBST or ASSIGN on '+
                                           SubDriveCh;
        UnknownDisk  : DTStr := ' - unlisted disk type';
        InvalidDrive : if not IsDriveLocal(DriveNum) then
                         DTStr := ' - remote or network drive'
                       else
                         DTStr := ' - drive not ready';
        NovellDrive  : DTStr := ' - Novelle network drive';
        CDRomDisk    : DTStr := ' - CD-ROM drive';
      else
        { Trap for GetDiskClass update to include new types}
        { before this routine is revised, and ensure that  }
        { a function result is always assigned.            }
        DTStr := 'unrecognized disk type';
      end; {case}
      DiskTypeString := DTStr;
    end;

    function DiskCapacity(DriveLetter : char) : longint;
    {-Return the disk capacity in number of bytes for the specified drive. }
    var
      DriveNum          : byte;
      BytesPerCluster,
      AvailClusters,
      TotalClusters,
      SectorsPerCluster,
      BytesPerSector    : word;
      TotalBytes        : longint;
    begin
      DiskCapacity := 0;
      if IsListedAsPhantom(DriveLetter) then
        Exit;
      DriveNum := DrvLtrToNum(DriveLetter);
      if GetDiskInfo(DriveNum,AvailClusters,TotalClusters,
                     BytesPerSector,SectorsPerCluster) then
        begin
          BytesPerCluster := LongInt(SectorsPerCluster) * BytesPerSector;
          DiskCapacity := LongInt(TotalClusters) * BytesPerCluster;
        end;
    end; { DiskCapacity }

    function DiskCapacityString(DriveLetter : Char) : String;
    {-Return disk capacity info in megabytes or gigabytes formatted with commas }
    var
      DiskCap : LongInt;
      TempStr : String;
    begin
      DiskCap := DiskCapacity(DriveLetter);
      if DiskCap >= Gigabyte then
        TempStr := Long2Str(DiskCap div Gigabyte)+'GB'
      else
        if DiskCap > 9*Megabyte then
          TempStr := InsertCommas(Long2Str(DiskCap div Megabyte))+'MB'
        else
          TempStr := Long2Str(DiskCap div Megabyte)+'.'+
               copy(Long2Str(DiskCap mod Megabyte),1,1)+'MB';
      DiskCapacityString := TempStr;
    end;

    function AvailableDriveSpace(DriveLetter : char) : longint;
    {-Return the number of bytes free on specified drive}
    var
      DriveNum            : byte;
      BytesPerCluster,
      AvailClusters,
      TotalClusters,
      SectorsPerCluster,
      BytesPerSector      : word;
      TotalBytes          : longint;
    begin
      AvailableDriveSpace := 0;
      if IsListedAsPhantom(DriveLetter) then
        Exit;
      DriveNum := DrvLtrToNum(DriveLetter);
      if GetDiskInfo(DriveNum,AvailClusters,TotalClusters,
                     BytesPerSector,SectorsPerCluster) then
        begin
          BytesPerCluster := LongInt(SectorsPerCluster) * BytesPerSector;
          AvailableDriveSpace := LongInt(AvailClusters) * BytesPerCluster;
        end;
    end; { AvailableDriveSpace }

    function DriveInfoString(DriveLetter : Char) : String;
    {-Return the formatted drive information for DriveLetter.  }
    { Use global variable ReportOptions to determine what data }
    { should be inlcuded in returned string. Return a nul      }
    { string if the drive's infor should not be displayed      }
    { per high or low options.                                 }
    var
      N  : Byte;
      InfoStr : String;
      ProcResult : Word;
      VolumeStr : VolumeNameStr;
      FreeSpace : LongInt;
      ShowThisDrive : Boolean;
    const
      SpacePadWidth = 13;
    begin
      InfoStr := 'Free '+DriveLetter+': ';
      if not IsListedAsPhantom(DriveLetter) then
        begin
          FreeSpace := AvailableDriveSpace(DriveLetter);
          InfoStr := InfoStr +
                      LeftPad(InsertCommas(Long2Str(FreeSpace)),SpacePadWidth);
        end
      else
        begin
          InfoStr := InfoStr + '  -----------';
          FreeSpace := 0;
        end;
      if FlagIsSet(ReportOptions,ShowSize) then
        if not IsListedAsPhantom(DriveLetter) then
          InfoStr := InfoStr + ' (Size '+ DiskCapacityString(DriveLetter) + ')'
        else
          InfoStr := InfoStr + ' (Size -----)';
      if FlagIsSet(ReportOptions,ShowType) then
        InfoStr := InfoStr + DiskTypeString(DriveLetter);
      if FlagIsSet(ReportOptions,ShowVolumeLabel) then
        if not IsListedAsPhantom(DriveLetter) then
          begin
            ProcResult := GetVolumeLabel(DriveLetter,VolumeStr);
            if ProcResult = 0 then
              if Length(VolumeStr) > 0 then
                InfoStr := InfoStr + '  '+VolumeStr
              else
                InfoStr := InfoStr + '  no label';
          end;

     { handle high and low disk space options }
      if FlagIsSet(ReportOptions,ShowAtOrAbove) or
         FlagIsSet(ReportOptions,ShowAtOrBelow) then
        begin  { allow both settings combined }
          ShowThisDrive := ( (FlagIsSet(ReportOptions,ShowAtOrAbove) and
                                 (FreeSpace >= HighDriveSpace)) or
                             (FlagIsSet(ReportOptions,ShowAtOrBelow) and
                                 (FreeSpace <= LowDriveSpace)) );
        end
      else
        ShowThisDrive := True;
      if not ShowThisDrive then
        DriveInfoString := ''
      else
        DriveInfoString := InfoStr;
    end;

    procedure DisplayDriveInfoString(DriveLetter : Char);
    {-Writeln DriveInfoString's result for DriveLetter if not a nul string }
    var
      DisplayStr : String;
    begin
      DisplayStr := DriveInfoString(DriveLetter);
      if Length(DisplayStr) > 0 then
        Writeln(DisplayStr);
    end;

    procedure DisplayDrivesInfo;
    {-Display the info for all drives in DriveList, checking ReportOptions   }
    { for display settings.                                                  }
    { Before calling DriveInfoString, make all calls to GetPhantomInfo.      }
    { DriveInfoString's call to GetDiskInfo will cause a disk in each drive, }
    { making any phantom drive current and thus undetectable by our methods. }
    { If a single drive was specified on the command line, and it turns out  }
    { to be a phantom drive, show the drive info for the mapped drive, too.  }
    var
      N : Byte;
    begin
     { build global list of phantom drive maps }
      for N := 1 to Length(DriveList) do
        GetAndSavePhantomInfo(DriveList[N]);

     { now get and display drive information }
     if (Length(DriveList) = 1) then
       begin  { hangle single specified phantom drive }
         DisplayDriveInfoString(DriveList[1]);
         if IsListedAsPhantom(DriveList[1]) then
           DisplayDriveInfoString(PhantomList[DriveList[1]].MapDrvLtr);
       end
     else    { show drive info for all listed drives }
      for N := 1 to Length(DriveList) do
        DisplayDriveInfoString(DriveList[N]);
     { pause if option enabled }
      if FlagIsSet(ReportOptions,ShowAndPause) then
        Delay(PauseDelaySecs*MsPerSec);
    end;

    function AllValidDrivesList : String;
    {-Return a string containing drive letters of all valid drives}
    var
      DriveLetter : Char;
      TempDrivesList : String;
      FirstDrive : Char;
    const
      LastDrive = 'Z';
    begin
      TempDrivesList := '';
      if FlagIsSet(ReportOptions,ShowFloppies) then
        FirstDrive := 'A'
      else
        FirstDrive := 'C';
      for DriveLetter := FirstDrive to LastDrive do
        if ValidDrive(DriveLetter) then
          TempDrivesList := TempDrivesList + DriveLetter
        else
      { primary floppies show invalid when last access was via the the Phantom }
      { drive, so check DOS equipment list for floppies by calling NumFloppies }
          if (DriveLetter in ['A','B']) and (NumFloppies > 0) then
            TempDrivesList := TempDrivesList + DriveLetter;
      AllValidDrivesList := TempDrivesList;
    end;

    function StripCommas(S : String) : String;
    {-Remove any commas from S and return as result }
    var
      LenS : Byte absolute S;
      P : Byte;
    begin
      for P := LenS downto 1 do
        if S[P] = ',' then
          Delete(S,P,1);
      StripCommas := S;
    end;

    procedure ParseCommandLine;
    {-Parse command line to get drive list and options }
    { First, check to see if a parameter is a drive letter or list of them.   }
    { If so, put the letter or letters in the drive list.                     }
    { If not a drive letter, the parameter should be a command option.        }
    { Process the command option, or ignore if not a valid option (could be   }
    { an option parameter or an invalid option).                              }
    var
      ChPos,Count   : Byte;
      TempDelaySecs : Word;
      Param,Param2  : String;
      ParamLen      : Byte absolute Param;
      Param2Len     : Byte absolute Param2;
      HLChar        : Char; { /HIGH, /LOW: K = Kbytes, M = Megabytes, G = Gig }
    const
      HLCharSet     : set of Char = ['G','K','M'];
    begin
     { initialize variables }
      FillChar(PhantomList, SizeOf(PhantomList), #0);
      ReportOptions := 0;
      HighDriveSpace := 0;
      LowDriveSpace := 0;
      for Count := 1 to ParamCount do
        begin
          Param := StUpCase(ParamStr(Count));
          if Param[1] in DriveLetterSet then
            begin
              for ChPos := 1 to ParamLen do  { for drives listed w/no spacing }
                if Pos(Param[ChPos],DriveList) = 0 then  { correct user error }
                  if ValidDrive(Param[ChPos]) then
                    DriveList := DriveList + Param[ChPos]
                  else
      { primary floppies show invalid when last access was via the the Phantom }
      { drive, so check DOS equipment list for floppies by calling NumFloppies }
                    if (Param[ChPos] in ['A','B']) and (NumFloppies > 0) then
                      DriveList := DriveList + Param[ChPos];
            end
          else
           { 1st char should be command delimiter }
           { 2nd char should indicate option      }
            if Param[1] in CommandDelimiters then
              begin
                case Param[2] of
                  'A' : SetFlag(ReportOptions,ShowAllDrives);
                  'F' : SetFlag(ReportOptions,ShowFloppies);
                  'H' : begin
                          HLChar := #255;  { to check if set }
                          if ParamCount <= Count then
                            HaltWithMessage('specify drive space with /HIGH option');
                          { check for G, K or M }
                          Param2 := StUpCase(ParamStr(Count+1));
                          if Param2[Param2Len] in HLCharSet then
                            begin
                              HLChar := Param2[Param2Len];
                              Delete(Param2,Param2Len,1);
                            end;
                          { validate free space number }
                          if not Str2Long(StripCommas(Param2),HighDriveSpace) then
                            HaltWithMessage('specify amount of drive space with /HIGH option')
                          else  { handle G, K or M }
                            if HLChar <> #255 then
                              begin
                                case HLChar of
                                  'G' : HighDriveSpace := HighDriveSpace * Gigabyte;
                                  'K' : HighDriveSpace := HighDriveSpace * Kbyte;
                                  'M' : HighDriveSpace := HighDriveSpace * Megabyte;
                                end; {case}
                              end;
                          SetFlag(ReportOptions,ShowAtOrAbove);
                          SetFlag(ReportOptions,ShowAllDrives);
                        end;
                  'L' : begin
                          HLChar := #255;  { to check if set }
                          if ParamCount <= Count then
                            HaltWithMessage('specify drive space with /LOW option');
                          { check for G, K or M }
                          Param2 := StUpCase(ParamStr(Count+1));
                          if Param2[Param2Len] in HLCharSet then
                            begin
                              HLChar := Param2[Param2Len];
                              Delete(Param2,Param2Len,1);
                            end;
                          { validate free space number }
                          if not Str2Long(StripCommas(Param2),LowDriveSpace) then
                            HaltWithMessage('specify amount of drive space with /LOW option')
                          else  { handle G, K or M }
                            if HLChar <> #255 then
                              begin
                                case HLChar of
                                  'G' : LowDriveSpace := LowDriveSpace * Gigabyte;
                                  'K' : LowDriveSpace := LowDriveSpace * Kbyte;
                                  'M' : LowDriveSpace := LowDriveSpace * Megabyte;
                                end; {case}
                              end;
                          SetFlag(ReportOptions,ShowAtOrBelow);
                          SetFlag(ReportOptions,ShowAllDrives);
                        end;
                  'P' : begin
                          SetFlag(ReportOptions,ShowAndPause);
                          if Count < ParamCount then  { next param could be delay }
                            if Str2Word(ParamStr(Count+1),TempDelaySecs) then
                                PauseDelaySecs := TempDelaySecs;
                        end;
                  'S' : SetFlag(ReportOptions,ShowSize);
                  'T' : SetFlag(ReportOptions,ShowType);
                  'V' : SetFlag(ReportOptions,ShowVolumeLabel);
                  '?' : ShowUsageAndHalt;
                end; { case }
              end;  { if Param[1] in CommandDelimiters }
        end; { for Count := 1 to ParamCount }
      if FlagIsSet(ReportOptions,ShowAllDrives) or
         FlagIsSet(ReportOptions,ShowFloppies) then
           DriveList := AllValidDrivesList;
    end; { ParseCommandLine }

    begin { FREE }
      RestoreOutputRedirection;
      if ParamCount > 0 then
        ParseCommandLine;
      if Length(DriveList) = 0 then  { if no drives on command line }
        DriveList := DefaultDrive;   { default to current the drive }
      DisplayDrivesInfo;
    end. { FREE }

[Back to DRIVES SWAG index] [Back to Main SWAG index] [Original]