IMPLEMENTATION MODULE Drectory; (* * REPERTOIRE * Release 1.6 * By Charles Bradford and Cole Brecheen * (c) Copyright 1985-1992 PMI * Green Bay, Wisconsin * All rights reserved * (414) 468-6040 * * $Header: D:/logfiles/mods/drectory.mov 1.8 17 Mar 1991 18:00:54 coleb $ * *) IMPORT ByteFiddler; IMPORT EnvironUtils; IMPORT ErrorManager; IMPORT HandleIO; IMPORT LowLevel; IMPORT M2Strings; IMPORT Numbers; IMPORT NumTypes; IMPORT PosUtils; IMPORT StrConv; IMPORT StrEdit; IMPORT StringIO; IMPORT VStorage; IMPORT FAPI; IMPORT SYSTEM; VAR Initialized : BOOLEAN; PROCEDURE Init(); BEGIN IF Initialized THEN RETURN; ELSE Initialized := TRUE; END; ByteFiddler.Init(); EnvironUtils.Init(); ErrorManager.Init(); HandleIO.Init(); LowLevel.Init(); M2Strings.Init(); Numbers.Init(); NumTypes.Init(); PosUtils.Init(); StrConv.Init(); StrEdit.Init(); StringIO.Init(); VStorage.Init(); END Init; CONST blank = ' '; null = ''; semicolon = ';'; backslash = '\'; fwdslash = '/'; byte1 = 0; OrdA = 65; TYPE ModeSetCaster = RECORD CASE : BOOLEAN OF TRUE : a : ModeSet; | FALSE : b : BITSET; END; END; (*==================== Utility Procedures =====================*) PROCEDURE LastByte( FileHandle: CARDINAL ): CHAR; VAR bufch: CHAR; BEGIN HandleIO.SetFilePtr(FileHandle, HandleIO.FromEnd, Numbers.Li( -1) ); StringIO.PrintMessage(HandleIO.BlockRead( FileHandle, SYSTEM.ADR(bufch), 1 )); RETURN bufch; END LastByte; (*================== Exported Procedures ==================*) PROCEDURE AddBlockToFile(FileName : ARRAY OF CHAR; FileHandle : CARDINAL; BlockAdr: SYSTEM.ADDRESS; BlockSize: CARDINAL ); VAR AlreadyOpen : BOOLEAN; EofChar: CHAR; BEGIN EofChar := CHR(26); IF (M2Strings.Length(FileName)=0) OR (FileHandle>4) THEN AlreadyOpen := TRUE; ELSE AlreadyOpen := FALSE; StringIO.PrintMessage(HandleIO.OpenFile(FileHandle,FileName)); END; IF LastByte( FileHandle ) = CHR(26) THEN HandleIO.SetFilePtr(FileHandle, HandleIO.FromEnd, Numbers.Li( -1) ); (*Back up to write over the eof.*) StringIO.PrintMessage( HandleIO.BlockWrite( FileHandle, BlockAdr, BlockSize )); StringIO.PrintMessage( HandleIO.BlockWrite( FileHandle, SYSTEM.ADR(EofChar), 1 )); (*Write a new eof.*) ELSE HandleIO.SetFilePtr(FileHandle, HandleIO.FromEnd, NumTypes.L0 ); (*Don't back up to write over the eof.*) StringIO.PrintMessage( HandleIO.BlockWrite( FileHandle, BlockAdr, BlockSize )); END; IF AlreadyOpen THEN HandleIO.UpdateDisk( FileHandle ) ELSE StringIO.PrintMessage(HandleIO.CloseHandle(FileHandle)); (*Updates the file's directory entry.*) END; END AddBlockToFile; PROCEDURE AddToFile(FileName : ARRAY OF CHAR; FileHandle : CARDINAL; message : ARRAY OF CHAR); BEGIN (*AddToFile*) AddBlockToFile( FileName, FileHandle, SYSTEM.ADR(message), M2Strings.Length(message) ); END AddToFile; PROCEDURE ChDir(DirName : ARRAY OF CHAR) : CARDINAL; VAR ErrorReturn :CARDINAL; Reserved:LONGINT; BEGIN ErrorReturn := FAPI.DOSCHDIR(SYSTEM.ADR(DirName), Reserved); RETURN ErrorReturn; END ChDir; PROCEDURE CopyFile(OldHandle : CARDINAL; NewFileName : ARRAY OF CHAR) : CARDINAL; TYPE memptr = RECORD addr : LowLevel.Address8086; size : CARDINAL; END; VAR TheDrive : CHAR; MemoryPtr : memptr; NewHandle : CARDINAL; SavedMessage : CARDINAL; FreeBytes, FileSize, BytesToBeFreed, BytesToRead : LONGINT; PROCEDURE ReadOldFile(VAR MemoryPtr : memptr); VAR BytesRead,ErrorReturn:CARDINAL; BytesAvailable : CARDINAL; BEGIN (*ReadOldFile*) IF BytesToRead <= Numbers.Lc( 0 ) THEN MemoryPtr.addr.x := NIL; RETURN; END; BytesAvailable := EnvironUtils.MemAvail( 10000); WITH MemoryPtr DO IF BytesToRead > Numbers.Lc( BytesAvailable ) THEN size := BytesAvailable; ELSE size := Numbers.C( BytesToRead ); END; VStorage.DosAlloc(addr.a, size); END; ErrorReturn := FAPI.DOSREAD(OldHandle, MemoryPtr.addr.a, MemoryPtr.size, SYSTEM.ADR(BytesRead)); IF BytesRead < MemoryPtr.size THEN IF BytesRead = 0 THEN StringIO.PrintMessage (StringIO.EndOfFile); ELSE StringIO.PrintMessage (StringIO.PartialRead); END; ELSE IF ErrorReturn # 0 THEN StringIO.PrintMessage(ErrorReturn); ELSE BytesToRead := BytesToRead - Numbers.Lc( MemoryPtr.size ); (* Can't use DEC here because JPI doesn't allow LONGINTs to be decremented by CARDINAL values. *) END; END; END ReadOldFile; PROCEDURE WriteNewFile(MemoryPtr : memptr); VAR ErrorReturn, BytesWritten: CARDINAL; BEGIN (*WriteNewFile*) IF MemoryPtr.addr.x=NIL THEN RETURN; END; ErrorReturn := FAPI.DOSWRITE( NewHandle, MemoryPtr.addr.a, MemoryPtr.size, SYSTEM.ADR(BytesWritten) ); IF BytesWritten < MemoryPtr.size THEN ErrorManager.WARN('No room to write.'); END; IF ErrorReturn # 0 THEN StringIO.PrintMessage(ErrorReturn); END; VStorage.DosDealloc(MemoryPtr.addr.x, MemoryPtr.size); END WriteNewFile; PROCEDURE SetDateAndTime(); VAR month, day, year, hours, minutes, seconds : CARDINAL; BEGIN GetFileDateAndTime(OldHandle, month, day, year, hours, minutes, seconds); (* Diagnostics.diagC( 'month', month ); Diagnostics.diagC( 'day', day ); Diagnostics.diagC( 'year', year ); Diagnostics.diagC( 'hours', hours ); Diagnostics.diagC( 'minutes', minutes ); Diagnostics.diagC( 'seconds', seconds ); *) SetFileDateAndTime(NewHandle, month, day, year, hours, minutes, seconds); END SetDateAndTime; BEGIN (*CopyFile*) BytesToBeFreed := Numbers.Lc( 0 ); FileSize := HandleIO.FileLength(OldHandle); BytesToRead := FileSize; IF M2Strings.Pos(':',NewFileName)=(1+byte1) THEN TheDrive := NewFileName[0+byte1]; ELSE TheDrive := 'Z'; (*Determines the drive to which we're copying. 'Z' means "default drive" to FreeDiskSpace.*) END; SavedMessage := FreeDiskSpace(TheDrive,FreeBytes); IF SavedMessage # StringIO.NoError THEN RETURN SavedMessage; END; SavedMessage := HandleIO.OpenFile(NewHandle,NewFileName); IF SavedMessage = StringIO.NoError THEN BytesToBeFreed := HandleIO.FileLength(NewHandle); SavedMessage := HandleIO.CloseHandle(NewHandle); ELSE IF (SavedMessage # StringIO.FileNotFound) AND (SavedMessage # 110) THEN (* explicit fail command *) RETURN SavedMessage; END; END; IF FileSize > (FreeBytes + BytesToBeFreed) THEN SavedMessage := StringIO.AccessDenied; (*This will have to stand for 'Not enough room.'*) RETURN SavedMessage; END; SavedMessage := HandleIO.CreateFile( NewHandle, NewFileName ); IF SavedMessage # StringIO.NoError THEN RETURN SavedMessage; END; REPEAT ReadOldFile(MemoryPtr); WriteNewFile(MemoryPtr); UNTIL BytesToRead <= Numbers.Lc( 0 ); SetDateAndTime(); RETURN HandleIO.CloseHandle(NewHandle); END CopyFile; (* We can't use this, unfortunately, because DOSCOPY isn't FAPI, and the Logitech linker can't handle unresolved symbols, even if the references aren't going to get linked in. PROCEDURE CopyFile2( SourceName, TargetName: ARRAY OF CHAR ): CARDINAL; VAR OldFileHandle, ErrorReturn, OSversion: CARDINAL; Reserved: LONGINT; BEGIN FAPI.DOSGETVERSION( SYSTEM.ADR(OSversion) ); IF OSversion >= 10 THEN (* We're under some version of OS/2 *) Reserved := NumTypes.L0; ErrorReturn := FAPI.DOSCOPY( SYSTEM.ADR(SourceName), SYSTEM.ADR(TargetName), BITSET(0), Reserved ); ELSE ErrorReturn := HandleIO.OpenFile( OldFileHandle, SourceName ); IF ErrorReturn # 0 THEN ErrorManager.WarnNumber( 'CopyFile2 error', ErrorReturn ); END; ErrorReturn := CopyFile( OldFileHandle, TargetName ); END; RETURN ErrorReturn; END CopyFile2; *) PROCEDURE DeleteFile(FileName : ARRAY OF CHAR) : CARDINAL; VAR ErrorReturn:CARDINAL; Reserved:LONGINT; LocalStr: ARRAY [0..79] OF CHAR; BEGIN M2Strings.Assign( FileName, LocalStr ); (*We assign to the local string to guarantee that it ends with a null byte.*) Reserved := VAL(LONGINT,0); ErrorReturn := FAPI.DOSDELETE(SYSTEM.ADR(FileName), Reserved); (* IF ErrorReturn # 0 THEN ErrorManager.WarnNumber( "DOSDELETE error", ErrorReturn ); END; let it return error JEM 2/4/92 *) RETURN ErrorReturn; END DeleteFile; PROCEDURE FindFirstFile(FileSpec : ARRAY OF CHAR; VAR DirHandle: CARDINAL; VAR FileInfo : FileInfoRec) : CARDINAL; VAR ErrorReturn : CARDINAL; Reserved : LONGINT; SearchCount : CARDINAL; FileInfoRecord : FAPI.FILEFINDBUF; TmpSet : FAPI.USHORT; TmpStr : ARRAY [0..80] OF CHAR; BEGIN (*FindFirstFile*) StrEdit.AssignStr(FileSpec, TmpStr); (*We have to assign to a local string because the string that comes in through the parameter list may not be null terminated. *) TmpSet := FAPI.FILE_READONLY + FAPI.FILE_HIDDEN + FAPI.FILE_SYSTEM + FAPI.FILE_DIRECTORY; SearchCount := 1; Reserved :=VAL(LONGINT,0); ErrorReturn := FAPI.DOSFINDFIRST( SYSTEM.ADR(TmpStr), SYSTEM.ADR(DirHandle), TmpSet, SYSTEM.ADR(FileInfoRecord), SYSTEM.SIZE(FileInfoRecord), SYSTEM.ADR(SearchCount), Reserved); IF ErrorReturn # 0 THEN RETURN ErrorReturn; END; WITH FileInfo DO ByteFiddler.CardinalToTime( CARDINAL(FileInfoRecord.ftimeLastWrite), hour, minute, second ); ByteFiddler.CardinalToDate( CARDINAL(FileInfoRecord.fdateLastWrite), month, day, year ); size := FileInfoRecord.cbFile; attribute := ModeSet(FileInfoRecord.attrFile); M2Strings.Assign( FileInfoRecord.achName, name ); END; RETURN StringIO.NoError; END FindFirstFile; PROCEDURE FindNextFile( DirHandle: CARDINAL; VAR FileInfo : FileInfoRec) : CARDINAL; VAR ErrorReturn : CARDINAL; Reserved : LONGINT; SearchCount : CARDINAL; FileInfoRecord : FAPI.FILEFINDBUF; BEGIN SearchCount := 1; ErrorReturn := FAPI.DOSFINDNEXT( DirHandle, SYSTEM.ADR(FileInfoRecord), SYSTEM.SIZE(FileInfoRecord), SYSTEM.ADR(SearchCount) ); IF ErrorReturn # 0 THEN RETURN ErrorReturn; END; WITH FileInfo DO ByteFiddler.CardinalToTime( CARDINAL(FileInfoRecord.ftimeLastWrite), hour, minute, second ); ByteFiddler.CardinalToDate( CARDINAL(FileInfoRecord.fdateLastWrite), month, day, year ); size := FileInfoRecord.cbFile; attribute := ModeSet(FileInfoRecord.attrFile); StrEdit.AssignStr( FileInfoRecord.achName, name ); END; RETURN StringIO.NoError; END FindNextFile; PROCEDURE FreeDiskSpace(DriveLetter : CHAR; VAR FreeBytes : LONGINT) : CARDINAL; VAR DriveNum, ErrorReturn: CARDINAL; Level1Data:FAPI.FSALLOCATE; BEGIN FreeBytes := Numbers.Lc( 0 ); DriveLetter := CAP(DriveLetter); IF (DriveLetter < 'A') OR (DriveLetter > 'Z') THEN (* 26 July 87: changed from AND at suggestion of Marc Scheuner and Gregor Kley. *) ErrorManager.WARN('Invalid drive specification'); END; IF DriveLetter='Z' THEN (*'Z' means default drive*) DriveNum := 0; ELSE DriveNum := ORD(DriveLetter)-64; END; (*turns an A into a 1, etc*) ErrorReturn := FAPI.DOSQFSINFO( DriveNum, 1, SYSTEM.ADR(Level1Data), SYSTEM.SIZE(Level1Data)); IF ErrorReturn # 0 THEN RETURN ErrorReturn; ELSE FreeBytes := (Level1Data.cUnitAvail) * (Numbers.Lc (Level1Data.cbSector) * Level1Data.cSectorUnit); RETURN StringIO.NoError; END; END FreeDiskSpace; PROCEDURE GetCurrentDir(TheDrive : CHAR; VAR ThePath : ARRAY OF CHAR) : CARDINAL; VAR ErrorReturn, PathLength, DriveNum:CARDINAL; cnt : CARDINAL; BEGIN TheDrive := CAP(TheDrive); IF TheDrive = 'Z' THEN DriveNum := 0; ELSE DriveNum := ((ORD(TheDrive)-OrdA)+1); END; PathLength := HIGH( ThePath ) + 1; ErrorReturn := FAPI.DOSQCURDIR(DriveNum, SYSTEM.ADR(ThePath), SYSTEM.ADR(PathLength) ); M2Strings.Insert( backslash, ThePath, 0 ); RETURN ErrorReturn; END GetCurrentDir; PROCEDURE GetDefaultDrive() : CHAR; (*Returns the current default drive as an upper case letter.*) VAR DriveNum, ErrorReturn: CARDINAL; LogicalDriveMap: FAPI.ULONG; BEGIN ErrorReturn := FAPI.DOSQCURDISK( SYSTEM.ADR(DriveNum), SYSTEM.ADR(LogicalDriveMap) ); IF ErrorReturn # 0 THEN ErrorManager.WarnNumber("DOSQCURDISK Error", ErrorReturn ); END; RETURN( CHR( ORD(DriveNum) + OrdA - 1 ) ); END GetDefaultDrive; PROCEDURE GetDiskInfo( TheDrive: CHAR; VAR BytesPerSector, SectorsPerCluster, ClustersOnDisk: CARDINAL; VAR KindOfDisk: DiskTypes ); VAR DriveNum, ErrorReturn: CARDINAL; FatIDByte: CHAR; Level1Data: FAPI.FSALLOCATE; BEGIN TheDrive := CAP(TheDrive); IF TheDrive = 'Z' THEN DriveNum := 0; ELSE DriveNum := (ORD(TheDrive) - OrdA) + 1; END; ErrorReturn := FAPI.DOSQFSINFO( DriveNum, 1, SYSTEM.ADR(Level1Data), SYSTEM.SIZE(Level1Data) ); IF ErrorReturn # 0 THEN ErrorManager.WarnNumber( "DOSQFSINFO error", ErrorReturn ); END; BytesPerSector := Level1Data.cbSector; SectorsPerCluster := Numbers.C(Level1Data.cSectorUnit); ClustersOnDisk := Numbers.C(Level1Data.cUnit); KindOfDisk := unknown; END GetDiskInfo; PROCEDURE GetDirFromList( PathStyleStr: ARRAY OF CHAR; whichDir: CARDINAL; VAR output: ARRAY OF CHAR ): BOOLEAN; VAR StartSpot, EndSpot, inStrLngth: CARDINAL; BEGIN inStrLngth := M2Strings.Length(PathStyleStr); output[0] := 0C; IF whichDir = 0 THEN RETURN( FALSE ); END; IF whichDir = 1 THEN StartSpot := LowLevel.ScanEQ( inStrLngth, '=', SYSTEM.ADR(PathStyleStr) ); IF StartSpot >= inStrLngth THEN StartSpot := 0; END; ELSE StartSpot := PosUtils.FindNthPattern(semicolon, whichDir - 1, PathStyleStr); IF StartSpot >= inStrLngth THEN RETURN( FALSE ); END; END; EndSpot := PosUtils.FindNthPattern(semicolon, whichDir, PathStyleStr); IF EndSpot >= inStrLngth THEN IF PosUtils.LastNonMatching(blank, PathStyleStr) = semicolon THEN RETURN( FALSE ); END; EndSpot := inStrLngth; END; (* At this point, EndSpot is either sitting on the trailing null or on the semicolon following the directory name we want to copy out. *) M2Strings.Copy( PathStyleStr, StartSpot, EndSpot - StartSpot, output ); IF PosUtils.LastNonMatching(blank, output) # backslash THEN StrEdit.Append( output, backslash ); END; RETURN( TRUE ); END GetDirFromList; PROCEDURE GetDrivePathAndName( FileSpec: ARRAY OF CHAR; VAR DriveLetter: CHAR; VAR PathName, FileName : ARRAY OF CHAR); VAR TmpStr : ARRAY [0..79] OF CHAR; spot: CARDINAL; SavedMessage: CARDINAL; BEGIN (*GetDrivePathAndName*) StrEdit.AssignStr( null, PathName ); StrEdit.AssignStr( null, FileName ); DriveLetter := 'Z'; spot := 0; WHILE spot+1 <= M2Strings.Length(FileSpec) DO IF FileSpec[spot] = ':' THEN DriveLetter := FileSpec[ spot - 1 ]; M2Strings.Delete(FileSpec, 0, 1 + spot); spot := 0; ELSIF (FileSpec[spot]=backslash) OR (FileSpec[spot]=fwdslash) THEN M2Strings.Copy(FileSpec, 0, spot + 1, TmpStr); StrEdit.Append(PathName, TmpStr); M2Strings.Delete(FileSpec, 0, 1 + spot); spot := 0; ELSE INC(spot); END; END; IF DriveLetter = 'Z' THEN DriveLetter := GetDefaultDrive(); END; IF M2Strings.Length(PathName) = 0 THEN SavedMessage := GetCurrentDir( DriveLetter, PathName ); IF SavedMessage # StringIO.NoError THEN StringIO.PrintMessage( SavedMessage ); HALT(); (*This error shouldn't be possible.*) END; IF PathName[ M2Strings.Length(PathName) - 1 ] # backslash THEN StrEdit.Append( PathName, backslash ); END; END; IF (M2Strings.Length(FileSpec) > 0) AND (NOT (PosUtils.Present('*', FileSpec))) AND (NOT (PosUtils.Present('?', FileSpec))) THEN StrEdit.AssignStr( FileSpec, FileName ); END; END GetDrivePathAndName; PROCEDURE GetFileDateAndTime(FileHandle : CARDINAL; VAR month, day, year, hours, minutes, seconds : CARDINAL); VAR ErrorReturn: CARDINAL; FileInfoRec: FAPI.FILEFINDBUF; BEGIN (*GetFileDateAndTime*) LowLevel.Fill( SYSTEM.ADR(FileInfoRec), SYSTEM.SIZE(FileInfoRec), 0C ); ErrorReturn := FAPI.DOSQFILEINFO( FileHandle, 1, SYSTEM.ADR(FileInfoRec), SYSTEM.SIZE(FileInfoRec) ); (* Diagnostics.diagC( 'FileHandle', FileHandle ); Diagnostics.diagC( 'fdateCreation', FileInfoRec.fdateCreation ); Diagnostics.diagC( 'ftimeCreation', FileInfoRec.ftimeCreation ); Diagnostics.diagC( 'fdateLastAccess', FileInfoRec.fdateLastAccess ); Diagnostics.diagC( 'ftimeLastAccess', FileInfoRec.ftimeLastAccess ); Diagnostics.diagC( 'fdateLastWrite', FileInfoRec.fdateLastWrite ); Diagnostics.diagC( 'ftimeLastWrite', FileInfoRec.ftimeLastWrite ); Diagnostics.diagL( 'file', FileInfoRec.file ); Diagnostics.diagL( 'fileAlloc', FileInfoRec.fileAlloc ); Diagnostics.diagC( 'attrFile', FileInfoRec.attrFile ); Diagnostics.diagC( 'cname', ORD(FileInfoRec.cname) ); Diagnostics.diagS( 'name', FileInfoRec.name ); Diagnostics.diagBlock( 'FileInfoRec', SYSTEM.ADR(FileInfoRec), SYSTEM.SIZE(FileInfoRec) ); *) IF ErrorReturn # 0 THEN ErrorManager.WarnNumber( "GetFileDateAndTime error ", ErrorReturn ); ELSE ByteFiddler.CardinalToTime( CARDINAL(FileInfoRec.ftimeLastWrite), hours, minutes, seconds ); ByteFiddler.CardinalToDate( CARDINAL(FileInfoRec.fdateLastWrite), month, day, year ); END; END GetFileDateAndTime; PROCEDURE GetFileMode(FileName : ARRAY OF CHAR; VAR TheSet : ModeSet) : CARDINAL; VAR ErrorReturn: CARDINAL; DosFileAttr: FAPI.USHORT; Reserved: LONGINT; TmpSet: ModeSetCaster; LocalStr: ARRAY [0..79] OF CHAR; BEGIN TmpSet.a := ModeSet{}; M2Strings.Assign( FileName, LocalStr ); ErrorReturn:= FAPI.DOSQFILEMODE(SYSTEM.ADR(LocalStr), SYSTEM.ADR(DosFileAttr), Reserved); IF ErrorReturn # 0 THEN TheSet := TmpSet.a; ErrorManager.WarnNumber("DosQFileMode error", ErrorReturn ); RETURN ErrorReturn; ELSE TmpSet.b := BITSET(CARDINAL(DosFileAttr)); TheSet := TmpSet.a; RETURN StringIO.NoError; END; END GetFileMode; PROCEDURE MkDir(DirName : ARRAY OF CHAR) : CARDINAL; VAR Reserved:LONGINT; ErrorReturn:CARDINAL; LocalStr: ARRAY [0..79] OF CHAR; BEGIN M2Strings.Assign( DirName, LocalStr ); ErrorReturn := FAPI.DOSMKDIR(SYSTEM.ADR(LocalStr),Reserved); RETURN ErrorReturn; END MkDir; PROCEDURE RenameFile(OldFileName, NewFileName : ARRAY OF CHAR) : CARDINAL; VAR ErrorReturn:CARDINAL; dumstr : ARRAY [0..5] OF CHAR; LocalStr1, LocalStr2: ARRAY [0..79] OF CHAR; BEGIN M2Strings.Assign( OldFileName, LocalStr1 ); M2Strings.Assign( NewFileName, LocalStr2 ); IF M2Strings.Pos(':',LocalStr2) = 1 THEN M2Strings.Delete(LocalStr2, 0, 2); END; IF M2Strings.Pos(':',LocalStr1) = 1 THEN M2Strings.Copy(LocalStr1, 0, 2, dumstr); (* 26 July 87: changed from 1, 2 at suggestion of Marc Scheuner and Gregor Kley. *) M2Strings.Insert(dumstr, LocalStr2, 0+byte1); END; ErrorReturn := FAPI.DOSMOVE( SYSTEM.ADR(LocalStr1), SYSTEM.ADR(LocalStr2), NumTypes.L0); RETURN ErrorReturn; END RenameFile; PROCEDURE RmDir(DirName : ARRAY OF CHAR) : CARDINAL; VAR ErrorReturn: CARDINAL; Reserved: LONGINT; LocalStr: ARRAY [0..79] OF CHAR; BEGIN M2Strings.Assign( DirName, LocalStr ); ErrorReturn := FAPI.DOSRMDIR(SYSTEM.ADR(LocalStr), Reserved); RETURN ErrorReturn; END RmDir; PROCEDURE SetDefaultDrive(DriveLetter : CHAR); (*Needs to return an ErrorMessage so that you can determine how many drives there are in the system.*) VAR ErrorReturn: CARDINAL; DriveNum: CARDINAL; BEGIN DriveLetter := CAP(DriveLetter); IF (DriveLetter<'A') OR (DriveLetter>'Z') THEN StringIO.PrintMessage(StringIO.InvalidDrive); END; DriveNum := (ORD(DriveLetter)-OrdA); ErrorReturn := FAPI.DOSSELECTDISK(DriveNum); IF ErrorReturn # 0 THEN StringIO.PrintMessage(ErrorReturn); END; END SetDefaultDrive; PROCEDURE SetFileDateAndTime(FileHandle, month, day, year, hours, minutes, seconds : CARDINAL); VAR ErrorReturn: CARDINAL; FileInfoRec: FAPI.FILEFINDBUF; BEGIN (*SetFileDateAndTime*) LowLevel.Fill( SYSTEM.ADR(FileInfoRec), SYSTEM.SIZE(FileInfoRec), 0C ); FileInfoRec.fdateLastWrite := FAPI.FDATE(ByteFiddler.DateToCardinal(month, day, year)); FileInfoRec.ftimeLastWrite := FAPI.FTIME(ByteFiddler.TimeToCardinal(hours, minutes, seconds)); ErrorReturn := FAPI.DOSSETFILEINFO( FileHandle, 1, SYSTEM.ADR(FileInfoRec), SYSTEM.TSIZE(FAPI.FILEFINDBUF) ); IF ErrorReturn # 0 THEN ErrorManager.WarnNumber( 'SetFileDateAndTime error', ErrorReturn ); END; END SetFileDateAndTime; PROCEDURE SetFileMode(FileName : ARRAY OF CHAR; TheSet : ModeSet) : CARDINAL; VAR ErrorReturn: CARDINAL; Reserved: LONGINT; TmpSet: ModeSetCaster; LocalStr: ARRAY [0..79] OF CHAR; BEGIN TmpSet.a := TheSet; M2Strings.Assign( FileName, LocalStr ); ErrorReturn := FAPI.DOSSETFILEMODE(SYSTEM.ADR(LocalStr), FAPI.FILE_NORMAL, Reserved); RETURN ErrorReturn; END SetFileMode; PROCEDURE SetFileLength( TheHandle:CARDINAL;length:LONGINT):CARDINAL; BEGIN RETURN FAPI.DOSNEWSIZE(TheHandle,length); END SetFileLength; PROCEDURE ValidFile( fname: ARRAY OF CHAR ): BOOLEAN; VAR TmpHandle: CARDINAL; ErrorReturn: CARDINAL; BEGIN IF HandleIO.FileExists( fname ) THEN RETURN TRUE; END; IF HandleIO.CreateFile( TmpHandle, fname ) = StringIO.NoError THEN ErrorReturn := HandleIO.CloseHandle(TmpHandle); ErrorReturn := DeleteFile( fname ); RETURN (ErrorReturn = StringIO.NoError); ELSE RETURN FALSE; END; END ValidFile; PROCEDURE VolumeLabel(TheDrive : CHAR; VAR TheLabel : ARRAY OF CHAR); (*Returns the label of the disk in TheDrive.*) VAR DriveNum, ErrorReturn: CARDINAL; Level2Data: FAPI.FSINFO; cnt : CARDINAL; nextchar : CHAR; BEGIN (*VolumeLabel*) TheDrive := CAP(TheDrive); IF TheDrive='Z' THEN DriveNum := 0; ELSE DriveNum := ORD(TheDrive) - OrdA + 1; (*sets 'A' to 1, 'B' to 2, etc.*) END; StrEdit.AssignStr(null, TheLabel); ErrorReturn := FAPI.DOSQFSINFO( DriveNum, 2, SYSTEM.ADR(Level2Data), SYSTEM.TSIZE(FAPI.FSINFO)); IF (ErrorReturn = 125) THEN (* DOSQFSINFO returns 125 if the drive has no volume label. In this case we set TheLabel to preserve compatibility with DOS version. *) StrEdit.AssignStr( 'unlabelled volume', TheLabel ); ELSIF (ErrorReturn # 0) THEN ErrorManager.WarnNumber( "DosQFSInfo error", ErrorReturn ); ELSE StrEdit.AssignStr( Level2Data.vol.szVolLabel, TheLabel ); END; END VolumeLabel; PROCEDURE FindFiles(FileName : ARRAY OF CHAR; FileProc : FileInfoProc) : CARDINAL; VAR info : FileInfoRec; DirHandle, result : CARDINAL; BEGIN DirHandle := 0FFFFH; result := FindFirstFile(FileName, DirHandle, info); IF result=StringIO.NoError THEN LOOP IF NOT FileProc(info) THEN EXIT; END; result := FindNextFile(DirHandle, info); IF result#StringIO.NoError THEN IF result = StringIO.NoMoreFiles THEN result := StringIO.NoError; END; EXIT; END; END; END; IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END; RETURN result; END FindFiles; BEGIN Initialized := FALSE; Init(); END Drectory.