MODULE DelOlder; IMPORT Diagnostics; IMPORT BigSets; IMPORT Drectory; IMPORT EnvironUtils; IMPORT ErrorManager; IMPORT HandleIO; IMPORT KbdInput; IMPORT M2Strings; IMPORT PosUtils; IMPORT StrConv; IMPORT StrEdit; IMPORT StringIO; VAR exiting, BatchMode : BOOLEAN; PrimaryFileSpec, SecondaryFileSpec, PrimaryDirName, SecondaryDirName, PrimaryFileSpecPart, SecondaryFileSpecPart: ARRAY [0..79] OF CHAR; PrimaryDrive, SecondaryDrive: CHAR; PROCEDURE Ask( question: ARRAY OF CHAR; VAR answer: ARRAY OF CHAR ); VAR tmpstr: ARRAY [0..79] OF CHAR; BEGIN StringIO.WriteStr( StringIO.outp, question ); IF answer[0] # 0C THEN (* There is a default. *) StringIO.WriteStr( StringIO.outp, ' <' ); StringIO.WriteStr( StringIO.outp, answer ); StringIO.WriteStr( StringIO.outp, '> ' ); END; StringIO.ReadStr( StringIO.inp, tmpstr ); IF tmpstr[0] = 0C THEN RETURN; END; IF (( CAP(tmpstr[0]) = 'Q' ) OR (tmpstr[0] = CHR(27))) AND (M2Strings.Length(tmpstr) = 1) THEN ErrorManager.StraightToDOS(''); END; M2Strings.Assign( tmpstr, answer ); END Ask; PROCEDURE FirstIsOlder( VAR First, Second: Drectory.FileInfoRec ): BOOLEAN; BEGIN IF First.year < Second.year THEN RETURN TRUE; ELSIF First.year > Second.year THEN RETURN FALSE; END; IF First.month < Second.month THEN RETURN TRUE; ELSIF First.month > Second.month THEN RETURN FALSE; END; IF First.day < Second.day THEN RETURN TRUE; ELSIF First.day > Second.day THEN RETURN FALSE; END; IF First.hour < Second.hour THEN RETURN TRUE; ELSIF First.hour > Second.hour THEN RETURN FALSE; END; IF First.minute < Second.minute THEN RETURN TRUE; ELSIF First.minute > Second.minute THEN RETURN FALSE; END; IF First.second < Second.second THEN RETURN TRUE; ELSE RETURN FALSE; END; END FirstIsOlder; PROCEDURE SameTimeStamp( VAR First, Second: Drectory.FileInfoRec ): BOOLEAN; BEGIN IF (First.year = Second.year) AND (First.month = Second.month) AND (First.day = Second.day) AND (First.hour = Second.hour) AND (First.minute = Second.minute) AND (First.second = Second.second) THEN RETURN TRUE; ELSE RETURN FALSE; END; END SameTimeStamp; PROCEDURE MakeInfoStr( FileInfo: Drectory.FileInfoRec; VAR TheStr: ARRAY OF CHAR ); VAR dumstr: ARRAY [0..79] OF CHAR; BEGIN StrEdit.AssignStr( FileInfo.name, TheStr ); WHILE M2Strings.Length(TheStr) < 12 DO StrEdit.Append( TheStr, ' ' ); END; IF Drectory.SubdirectoryFile IN FileInfo.attribute THEN StrEdit.Append( TheStr, ' ' ); ELSE StrConv.LongIntegerToStr( FileInfo.size, 8, dumstr ); StrEdit.Append( TheStr, dumstr ); END; StrConv.DateToStr( FileInfo.month, FileInfo.day, FileInfo.year, dumstr ); StrEdit.Append( TheStr, ' ' ); StrEdit.Append( TheStr, dumstr ); StrConv.TimeToStr( FileInfo.hour, FileInfo.minute, FileInfo.second, FileInfo.second, dumstr ); M2Strings.Delete( dumstr, M2Strings.Length(dumstr) - 7, 6 ); StrEdit.Append( TheStr, ' ' ); StrEdit.Append( TheStr, dumstr ); END MakeInfoStr; PROCEDURE yes() : BOOLEAN; VAR choice : CARDINAL; BEGIN (*yes*) IF BatchMode THEN StringIO.WriteStr( StringIO.outp, 'yes'); RETURN TRUE; END; choice := KbdInput.KeyHit( KbdInput.YorN ); IF KbdInput.CAPkey(choice) = ORD('Y') THEN StringIO.WriteStr( StringIO.outp, 'yes'); RETURN TRUE; ELSE StringIO.WriteStr( StringIO.outp, 'no'); IF KbdInput.CAPkey(choice) = ORD('Q') THEN exiting := TRUE; END; RETURN FALSE; END; END yes; PROCEDURE Processor1(info : Drectory.FileInfoRec) : BOOLEAN; VAR TmpPrimaryFile, TmpSecondaryFile, PrimaryInfoStr, SecondaryInfoStr: ARRAY [0..79] OF CHAR; DirHandle: CARDINAL; tmpinfo: Drectory.FileInfoRec; BEGIN IF PosUtils.Equal( '..', info.name ) OR PosUtils.Equal( '.', info.name ) THEN RETURN TRUE; END; M2Strings.Concat( PrimaryDirName, info.name, TmpPrimaryFile ); M2Strings.Concat( SecondaryDirName, info.name, TmpSecondaryFile ); M2Strings.Insert( ':', TmpPrimaryFile, 0 ); M2Strings.Insert( PrimaryDrive, TmpPrimaryFile, 0 ); M2Strings.Insert( ':', TmpSecondaryFile, 0 ); M2Strings.Insert( SecondaryDrive, TmpSecondaryFile, 0 ); IF HandleIO.FileExists( TmpSecondaryFile ) THEN MakeInfoStr( info, PrimaryInfoStr ); DirHandle := 0FFFFH; StringIO.PrintMessage( Drectory.FindFirstFile( TmpSecondaryFile, DirHandle, tmpinfo ) ); MakeInfoStr( tmpinfo, SecondaryInfoStr ); IF ((M2Strings.CompareStr( PrimaryInfoStr, SecondaryInfoStr ) = 0) OR FirstIsOlder( tmpinfo, info ) OR SameTimeStamp( tmpinfo, info) ) AND (NOT PosUtils.Present('', PrimaryInfoStr) ) THEN M2Strings.Insert( PrimaryDirName, PrimaryInfoStr, 0 ); M2Strings.Insert( ':', PrimaryInfoStr, 0 ); M2Strings.Insert( PrimaryDrive, PrimaryInfoStr, 0 ); M2Strings.Insert( SecondaryDirName, SecondaryInfoStr, 0 ); M2Strings.Insert( ':', SecondaryInfoStr, 0 ); M2Strings.Insert( SecondaryDrive, SecondaryInfoStr, 0 ); StrEdit.Append( SecondaryInfoStr, ' ' ); StringIO.WriteEol( StringIO.outp, '' ); StringIO.WriteStr( StringIO.outp, 'Keeping ' ); StringIO.WriteEol( StringIO.outp, PrimaryInfoStr ); StringIO.WriteStr( StringIO.outp, 'Delete? ' ); StringIO.WriteStr( StringIO.outp, SecondaryInfoStr ); IF yes() THEN StringIO.PrintMessage( Drectory.DeleteFile( TmpSecondaryFile ) ); END; IF exiting THEN RETURN FALSE; END; END; END; RETURN TRUE; END Processor1; BEGIN IF NOT EnvironUtils.ParsedParam( 1, PrimaryFileSpec ) THEN StringIO.WriteEol( StringIO.outp, '' ); StringIO.WriteEol( StringIO.outp, 'DelOlder expects two wildcard specifications of files in different' ); StringIO.WriteEol( StringIO.outp, 'directories. It deletes all files in the second directory with ' ); StringIO.WriteEol( StringIO.outp, 'names that match those of files in the first directory if the ' ); StringIO.WriteEol( StringIO.outp, 'secondary files are identical to or older than the primary files. A ' ); StringIO.WriteEol( StringIO.outp, 'trailing /p makes it pause for confirmation before deleting each file.' ); StringIO.WriteEol( StringIO.outp, '' ); PrimaryFileSpec := ''; Ask( 'Primary file specification? (These files will survive.) ', PrimaryFileSpec ); END; IF NOT EnvironUtils.ParsedParam( 2, SecondaryFileSpec ) THEN SecondaryFileSpec := ''; Ask( 'Secondary file specification? (These files may be deleted.) ', SecondaryFileSpec ); END; StrEdit.CrunchBlanks( PrimaryFileSpec ); StrEdit.CrunchBlanks( SecondaryFileSpec ); IF SecondaryFileSpec[M2Strings.Length(SecondaryFileSpec)-2]='/' THEN IF CAP( SecondaryFileSpec[M2Strings.Length(SecondaryFileSpec)-1] ) = 'P' THEN M2Strings.Delete(SecondaryFileSpec, M2Strings.Length(SecondaryFileSpec)-2, 2); StrEdit.CutTrailingChars( ' ', SecondaryFileSpec); BatchMode := FALSE; ELSE BatchMode := TRUE; END; ELSE BatchMode := TRUE; END; BigSets.AppendSet( KbdInput.YorN, "{'q', 'Q'}" ); Drectory.GetDrivePathAndName( SecondaryFileSpec, SecondaryDrive, SecondaryDirName, SecondaryFileSpecPart ); Drectory.GetDrivePathAndName( PrimaryFileSpec, PrimaryDrive, PrimaryDirName, PrimaryFileSpecPart ); IF PosUtils.Equal( PrimaryFileSpecPart, '.' ) THEN StringIO.PrintMessage( Drectory.GetCurrentDir( Drectory.GetDefaultDrive(), PrimaryDirName ) ); END; IF PosUtils.Equal( SecondaryFileSpecPart, '.' ) THEN StringIO.PrintMessage( Drectory.GetCurrentDir( Drectory.GetDefaultDrive(), SecondaryDirName ) ); END; IF PrimaryFileSpecPart[0] = 0C THEN PrimaryFileSpecPart := '*.*'; END; IF SecondaryFileSpecPart[0] = 0C THEN SecondaryFileSpecPart := '*.*'; END; StrEdit.CutTrailingChars( '\', PrimaryDirName ); StrEdit.CutTrailingChars( '\', SecondaryDirName ); StrEdit.Append( PrimaryDirName, '\' ); StrEdit.Append( SecondaryDirName, '\' ); exiting := FALSE; StringIO.PrintMessage(Drectory.FindFiles( PrimaryFileSpec, Processor1 )); END DelOlder.