[Back to DIRS SWAG index] [Back to Main SWAG index] [Original]
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* NUKE.PAS by Shane Kerr *
* Deletes a subdirectory and everything it contains. *
* Nuke for DOS written Turbo Pascal 5.5 *
* Nuke for Windows written using Turbo Pascal for Windows 1.0 *
* Version 1.95 November 23, 1991 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
program Nuke;
uses
{$IFDEF MsDos}
DOS;
{$ENDIF}
{$IFDEF Windows}
WinCRT, WinDOS, Strings;
{$ENDIF}
const
MajorVer = '1'; { Current major version number }
MinorVer = '95'; { Current minor version number }
Year = 1991; { Release year }
{$IFDEF MsDos}
fsDirectory = 64; { Set directory length }
faReadOnly = ReadOnly; { Set directory flags }
faHidden = Hidden;
faSysFile = SysFile;
faVolumeID = VolumeID;
faDirectory = Directory;
faArchive = Archive;
faAnyFile = AnyFile;
{$ENDIF}
{$IFDEF MsDos}
type
TRegisters = Registers; { Used for DOS calls }
TSearchRec = SearchRec; { Used for search record }
{$ENDIF}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* procedure FCBDeleteFile (FileSpec : string);
* Deletes files using the MS-DOS FCB function (from Version 1.0).
* parameters: filespec, file(s) to be deleted
* notes: Can only delete files in the current directory.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure FCBDeleteFile (filespec : string);
type
TFCB = record
drive : char; { 0 = default, 1 = A, 2 = B }
name : array[0..7] of char; { File name }
ext : array[0..2] of char; { File extension }
curblk : word; { Current block number }
recsize : word; { Logical record size in bytes }
filsize : longint; { File size in bytes }
date : word; { Date file was last written }
resv : array[0..10] of byte; { Reserved for DOS }
currec : byte; { Current record in block }
random : longint; { Random record number }
end;
var
FCB : TFCB;
Regs : TRegisters;
TempStr : string;
NameSeg, NameOfs : word;
FCBSeg, FCBOfs : word;
begin
{ Get segment and offset of the filespec }
TempStr := filespec + chr(0);
NameSeg := seg(TempStr);
NameOfs := ofs(TempStr) + 1;
FCBSeg := seg(FCB);
FCBOfs := ofs(FCB);
{ Do the actual DOS calls }
Regs.AX := $2900;
Regs.DS := NameSeg;
Regs.SI := NameOfs;
Regs.ES := FCBSeg;
Regs.DI := FCBOfs;
MsDos(Regs); { Parse file to FCB }
Regs.DS := FCBSeg;
Regs.DX := FCBOfs;
Regs.AH := $13;
MsDos(Regs); { Delete file (FCB) }
end; { FCBDeleteFile }
{$IFDEF MsDos}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* procedure ClearKb
* Clears the keyboard buffer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure ClearKb;
var
Regs : TRegisters;
begin
Regs.AH := $01;
Intr($16, Regs);
while ((Regs.Flags and FZero) = 0) do
begin
Regs.AH := $00;
Intr($16, Regs);
Regs.AH := $01;
Intr($16, Regs);
end;
end; { procedure ClearKb }
{$ENDIF}
{$IFDEF MsDos}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* procedure WaitKey
* Waits for a key press
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure WaitKey;
var
Regs : TRegisters;
begin
Regs.AH := $00;
Intr($16, Regs);
end; { procedure WaitKey }
{$ENDIF}
{$IFDEF MsDos}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* function IsRedirected : boolean;
* Determines whether a program's input or output is redirected
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function IsRedirected : boolean;
var
Regs : Registers; { Register values }
StdIn : ^Byte; { Standard input }
StdOut : ^Byte; { Standard output }
begin
Regs.AH := $62; { Get segment address of PSP }
MsDos(Regs);
StdIn := Ptr(Regs.BX, $18); { Point to StdIn value }
StdOut := Ptr(Regs.BX, $19); { Point to StdOut value }
{ Return TRUE if StdIn is the same as StdOut }
IsRedirected := (StdIn^ <> StdOut^);
end;
{$ENDIF}
{$IFDEF MsDos}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* function NumRows : byte;
* Returns the number of rows on the screen
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function NumRows : byte;
var
ScreenWidth : word absolute $0040:$004A;
ScreenSize : word absolute $0040:$004C;
begin
NumRows := (((ScreenSize div 1000) * 1000) div 2) div ScreenWidth;
end;
{$ENDIF}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* function NukeDir (directory : string) : boolean; *
* Destroys the specified directory and all it contains recursively *
* parameters: directory, path of the directory to be destroyed *
* remove, TRUE to remove directory *
* display, TRUE to display files as they are deleted *
* pause, TRUE to pause after each screen *
* attr, file search attributes to delete *
* lines, number of lines displayed so far *
* returns: TRUE if directory is removed, FALSE otherwise *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function NukeDir (directory : string; remove, display, pause : boolean;
attrib : word; var lines : word) : boolean;
var
OrgDir : string[fsDirectory]; { Saved original directory }
SrchRec : TSearchRec; { For file searches }
Dummy : boolean;
Handle : file; { File handle (for attrib change) }
begin
GetDir(0, OrgDir); { Get original directory }
ChDir(directory); { Change to target directory }
{ If display isn't on, just delete everything (grumble) }
if (not display) then
FCBDeleteFile('????????.???'); { Delete all files }
{ Find first file present }
FindFirst('*.*', faDirectory or attrib, SrchRec);
{ Loop and nuke any subdirectories found }
repeat
if (((SrchRec.Attr and faDirectory) <> 0) and (DosError = 0) and
{$IFDEF MsDos}
(SrchRec.Name[1] <> '.')) then
{$ENDIF}
{$IFDEF Windows}
(SrchRec.Name[0] <> '.')) then
{$ENDIF}
begin
Assign(Handle, SrchRec.Name);
SetFAttr(Handle, faDirectory);
Dummy := NukeDir(SrchRec.Name, TRUE, Display, Pause, Attrib, Lines);
end
else if ((DosError = 0) and
{$IFDEF MsDos}
(SrchRec.Name[1] <> '.') and
{$ENDIF}
{$IFDEF Windows}
(SrchRec.Name[0] <> '.') and
{$ENDIF}
(((SrchRec.Attr and Attrib) <> 0) or (Attrib = 0))) then
begin
Assign(Handle, SrchRec.Name);
SetFAttr(Handle, 0);
Erase(Handle);
{ If displaying, then show name and increase line count }
if (Display) then
begin
WriteLn(' Deleting ', Directory, '\', SrchRec.Name);
Inc(Lines);
end;
{ If pausing, check line count }
if (Pause and ((Lines mod (NumRows - 2)) = 0)) then
begin
Write('Press any key to continue...');
WaitKey;
WriteLn;
end;
end; { if block }
FindNext(SrchRec);
until (DosError <> 0);
{ If original directory is current, change to parent }
if (OrgDir = Directory) then
ChDir('..')
else if (pos(Directory, OrgDir) = 1) then
begin
ChDir(Directory);
ChDir('..');
end
else
ChDir(OrgDir); { Restore directory }
NukeDir := FALSE;
if (Remove) then
begin
{$I-}
RmDir(Directory); { Kill target directory }
if (IOResult = 0) then
NukeDir := TRUE;
{$I+}
end;
end; { function NukeDir }
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* function ToUpper (Str : string) : string; *
* Convert string to upper case *
* parameters: Str, any string *
* returns: uppercase value of the string *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function ToUpper (Str : string) : string;
var
i : integer;
Temp : string;
begin
Temp := str;
for i := 1 to length(Str) do
Temp[i] := UpCase(Temp[i]);
ToUpper := Temp;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* function ListFiles (directory : string) : integer *
* Lists files and attributes in the specified directory below *
* parameters: directory, directory to start listing at *
* returns: number of files listed *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function ListFiles (directory : string) : integer;
var
OrgDir : string; { Original directory }
CurDir : string; { Current directory }
SearchRec : TSearchRec; { Used to find filespecs }
NumListed : Integer; { Number of files listed }
Attr: word; { Attributes to remove }
begin
NumListed := 0; { Number of files listed }
GetDir(0, OrgDir); { Get original directory }
ChDir(directory); { Change to target directory }
GetDir(0, CurDir); { Get current directory }
{ Find first directory present }
FindFirst('*.*', faDirectory or faReadOnly or faHidden or faSysFile,
SearchRec);
FindNext(SearchRec);
FindNext(SearchRec);
{ Loop and list any files found }
repeat
if ((DosError = 0) and ((SearchRec.Attr and faDirectory) <> 0)) then
begin
NumListed := NumListed + ListFiles(SearchRec.Name);
end;
if (DosError = 0) then
begin
NumListed := NumListed + 1;
Write(' ', CurDir, '\', SearchRec.Name);
if ((SearchRec.Attr and faDirectory) <> 0) then
Write(', directory');
if ((SearchRec.Attr and faReadOnly) <> 0) then
Write(', read-only');
if ((SearchRec.Attr and faHidden) <> 0) then
Write(', hidden');
if ((SearchRec.Attr and faSysFile) <> 0) then
Write(', system');
WriteLn;
end; { if }
FindNext(SearchRec);
until (DosError <> 0);
ChDir(OrgDir); { Restore directory }
ListFiles := NumListed; { Return number of files listed }
end; { procedure ListFiles }
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* function HasSwitch (switch : string) : boolean *
* Checks the command-line arguements for the specified switch *
* parameters: switch, the switch to search for *
* returns: TRUE if found, else FALSE *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function HasSwitch (switch : char) : boolean;
var
i : integer; { Index variable }
begin
HasSwitch := FALSE;
for i := 1 to ParamCount-1 do
begin
if (Pos(UpCase(switch), ToUpper(ParamStr(i))) <> 0) then
begin
HasSwitch := TRUE;
Exit;
end; { if }
end; { for }
end; { function HasSwitch }
var { main variables }
UserInput : string[fsDirectory]; { user response }
Answer : string; { user response }
OrgDir : string[fsDirectory]; { Original directory }
Target : string[fsDirectory]; { Directory to nuke }
Remove : boolean; { If directory actually removed }
Result : boolean; { Result of nuking }
LinesShown : word; { Number of lines shown so far }
Attrib : word; { File attributes to delete }
begin { main program }
{ Print greeting }
WriteLn('NUKE Directory ', MajorVer, '.', MinorVer);
WriteLn(' (C)', Year, ' by Kerr');
WriteLn;
{ Check for DOS help command }
if ((ParamCount < 1) or HasSwitch('?') or (Pos('?', ParamStr(1)) <> 0)) then
begin
Write('Removes a subdirectory, along with the files and ');
WriteLn('subdirectories is contains');
WriteLn;
WriteLn('NUKE [options] [directory]');
WriteLn;
WriteLn('Options are as follows:');
WriteLn(' K Keeps the subdirectory after clearing out files.');
WriteLn(' H Deletes hidden files.');
WriteLn(' R Deletes read-only files.');
WriteLn(' S Deletes system files.');
WriteLn(' A Deletes files of all attributes.');
WriteLn(' Y No verification before NUKEing - dangerous!');
Write (' V Verbose, displays files and subdirectories they ');
WriteLn('are removed - SLOW!');
WriteLn(' P Pause after each screen.');
WriteLn;
WriteLn('You cannot nuke the root directory.');
WriteLn('Nuke will not Pause if you redirect the input or output.');
Exit;
end;
{ Set number of lines displayed }
LinesShown := 0;
{ Check for /K switch }
Remove := not HasSwitch('K');
Attrib := 0;
{ Check for /H switch }
if (HasSwitch('H')) then
Attrib := Attrib or faHidden;
{ Check for /R switch }
if (HasSwitch('R')) then
Attrib := Attrib or faReadOnly;
{ Check for /S switch }
if (HasSwitch('S')) then
Attrib := Attrib or faSysFile;
{ Check for /A switch }
if (HasSwitch('A')) then
if (Attrib <> 0) then
begin
WriteLn('Cannot use the /A switch with other attribute switches.');
Exit;
end
else
Attrib := faAnyFile;
{$IFDEF MsDos}
UserInput := ParamStr(ParamCount);
{$ENDIF}
{$IFDEF Windows}
Write('Input directory to remove: ');
ReadLn(UserInput);
{$ENDIF}
{ Save directory and drive and try to change to new directory }
GetDir(0, OrgDir);
{$I-}
ChDir(UserInput);
if (IOResult <> 0) then
begin
WriteLn(' Specified directory not found!');
ChDir(OrgDir);
Exit;
end;
{$I+}
GetDir(0, Target); { Get new directory }
{ Display target directory and change back from it }
WriteLn(' Target is ', Target);
WriteLn;
ChDir(OrgDir); { Restore directory }
{ Exit if root directory being nuked }
if (length(Target) = 3) then
begin
WriteLn('You cannot NUKE the root directory!');
WriteLn(' (Try FORMAT...)');
Exit;
end;
{ Double check before DECIMATING directory }
if (not HasSwitch('Y')) then
begin
WriteLn(' Are you SURE you want to OBLITERATE this directory and');
Write(' everything in or under it?!?!? (Y/N) ');
{$IFDEF MsDos}
ClearKb;
{$ENDIF}
ReadLn(Answer);
Answer := ToUpper(Answer);
end;
{ If 'yes' or 'y' entered, or 'Y' SWITCH set, nuke that puppy }
if ((answer = 'YES') or (answer = 'Y') or HasSwitch('Y')) then
begin
WriteLn(' Beginning now...');
Result := NukeDir(Target, Remove, HasSwitch('V'),
HasSwitch('P') and (not IsRedirected), Attrib, LinesShown);
WriteLn(' ...may the diety of your choice have mercy on your soul.');
end { if }
else
begin
Result := FALSE;
WriteLn(' Nothing done.');
Exit;
end; { else }
{ List files not deleted }
if (not Result) then
begin
WriteLn;
{ Display a message if the directory was SUPPOSED to be removed }
if (Remove) then
begin
WriteLn(' NUKE failed to remove the directory.');
end
else
begin
WriteLn(' NUKE has kept the directory.');
end;
WriteLn(' The following files or directories remain in it:');
if (ListFiles(Target) = 0) then
WriteLn(' None');
{ Display helpful hint if the directory was SUPPOSED to be removed }
if (Remove) then
begin
WriteLn;
Write('If you wish to remove these files, try the ');
WriteLn('/H, /R, and /S options,');
WriteLn(' or the /A option.');
end;
end; { if }
end. { main }
[Back to DIRS SWAG index] [Back to Main SWAG index] [Original]