{$ Include ../cdefines.inc}
Unit cfileUtils;
{}
{File Utility Functions V3.02}
{}
{THIS UNIT IS COPYRIGHT? 2002-2004 by David J Butler}
{}
{THIS UNIT IS Part of Delphi Fundamentals.
{ITS Original File Name is cfileUtils.pas}
{The Latest Version IS Available from The Fundamentals Home Page}
{http://fundementals.sourceforge.net/}
{}
{I invite you to use this unit, free of charge.
{I invite you to distibute this unit, but it must be for free.
{I also invite you to controle to its development,}
{But do not distribute a modified copy of this file.
{}
{A forum is available on sourceforge for general discussion}
{http://sourceforge.net/forum/forum.php?forum_id=2117}
{}
{Revision History:}
{01/06/2002 3.01 created cfileUtils from csysutils.
{12/12/2002 3.02 revision.} {}
Interface
Uses
{DELPHI}
{$ IFDEF OS_MSWIN}
Windows,
{$ ENDIF}
Sysutils;
{}
{Path functions}
{}
Const
Pathseperator = {$ IFDEF OS_Unix} '/' {$ ENDIF}
{$ IFDEF OS_MSWIN} '/' {$ ENDIF};
Function PathhasDriveletter (const path: string): boolean;
Function PathioDriveletter (const path: string): boolean;
Function PathisdriveRoot (const path: string): boolean;
Function Pathisroot (const path: string): boolean;
Function Pathisuncpath (const path: string): boolean;
Function Pathisabsolute (const path: string): boolean;
Function PathiSdirectory (const path: string): boolean;
Function Pathinclsuffix (const path: string;
Const Pathsep: char = PATHSEPERATOR): String;
Function patrsuffix (const path: string)
Const Pathsep: char = PATHSEPERATOR): String;
Procedure PATHENSURESUFFIX (VAR path: string;
Const Pathsep: char = pathseperator);
Procedure PATHENSURENOSUFFIX (VAR path: string;
Const Pathsep: char = pathseperator);
Function Pathcanonical (const path: string)
Const Pathsep: char = PATHSEPERATOR): String;
Function PATHEXPAND (Const Path: String; Const Basepath: String = ';
Const Pathsep: char = PATHSEPERATOR): String;
Function PathlefTelement (const path: string)
Const Pathsep: char = PATHSEPERATOR): String;
Procedure PathSplitlefTelement (const path: string) (CONST PATH: STRIN)
Var Leftelement, RightPath: String; const pathsep: char = pathseperator;
Procedure decodefilepath (const filepath: String;
Var path, filename: string
Const Pathsep: char = pathseperator);
Function FileNameValid (const filename: string): String;
Function Filepath (Const filename, Path: string; const basepath: string = ';
Const Pathsep: char = PATHSEPERATOR): String;
Function DirectoryExpand (Const Path: String; Const Basepath: String = ';
Const Pathsep: char = PATHSEPERATOR): String;
Function UNIXPathtowinPath (const path: string): String;
Function WinPathTounixPath (const path: string): String;
{}
{File Operations}
{Movefile First Attempts a rename, THEN A Copy and delete.}
{}
Type
EfileError = Class (Exception);
Function GetFileSize (const filename: string): int64;
Function GetFileDateTime (const filename: string): tdatetime;
Function GetFirstFileNameMatch (const filemask: string): String;
Function DirentrygetTR (const filename: string): integer;
Function DirentryiSdirectory (const filename: string): boolean;
Function FileHasattr (Const FileName: String; Const Attr: Word): Boolean
Function FileisreadOnly (const filename: string): boolean;
Procedure Copyfile (Const filename); Destname: String
Procedure Movefile (Const filename); Destname: String
Function deletefiles (const filemask: string): boolean;
{$ IFDEF OS_MSWIN}
{}
{Logical Drive functions} {}
Type
TLOGICALDRIVETYPE =
Driveremovable,
Drivefixed,
Driveremote,
Drivecdrom,
Driveramdisk,
DriveTypeunkNown;
Function DriveiSvalid (const drive: char): boolean;
Function DrivegetType (const path: string): TLOGICALDRIVETYPE;
Function DriveFreespace (const path: string): int64;
{$ ENDIF}
{}
{Self-testing code}
{}
Procedure Selftest;
IMPLEMENTATION
Uses
{Fundamentals}
CUTILS,
CSTRINGS;
{}
{Path functions}
{}
Function PathhasDriveletter (const path: string): boolean;
VAR P: PCHAR;
Begin
Result: = FALSE;
If longth (path) <2 THEN
EXIT;
P: = POINTER (PATH);
IF not (p ^ in ['a' .. 'z', 'a' .. 'z']) THEN
EXIT;
INC (P);
IF P ^ <> ':' Then
EXIT;
RESULT: = TRUE;
END;
Function PathioDriveletter (const path: string): boolean;
Begin
Result: = (Length (PATH) = 2) And PathhasDriveletter (PATH);
END;
Function PathisdriveRoot (const path: string): boolean;
Begin
Result: = (Length (PATH) = 3) And PathhasDriveletter (PATH) AND
(PATH [3] = '/');
END;
Function Pathisroot (const path: string): boolean;
Begin
Result: = ((Length (PATH) = 1) AND (Path [1] In Csslash) ORPATHISDRIVEROOT (PATH);
END;
Function Pathisuncpath (const path: string): boolean;
VAR P: PCHAR;
Begin
Result: = FALSE;
If longth (path) <2 THEN
EXIT;
P: = POINTER (PATH);
IF P ^ <> '/' THEN
EXIT;
INC (P);
IF P ^ <> '/' THEN
EXIT;
RESULT: = TRUE;
END;
Function Pathisabsolute (const path: string): boolean;
Begin
IF path = '' THEN
Result: = FALSE ELSE
IF pathhasdriveletter (path) THEN
Result: = True Else
IF pchar (POinter (Path) ^ in ['/', '/'] THEN
Result: = True Else
Result: = FALSE;
END;
Function PathiSdirectory (const path: string): boolean;
Var l: integer;
P: pchar;
Begin
L: = Length (path);
IF l = 0 THEN
Result: = FALSE ELSE
IF (l = 2) and pathhasdriveletter (path) THEN
Result: = True Else
Begin
P: = POINTER (PATH);
INC (P, L - 1);
Result: = p ^ in Csslash;
END;
END;
Function Pathinclsuffix (const path: string; const pathsep: char): string;
Var l: integer;
P: pchar;
Begin
L: = Length (path);
IF l = 0 THEN
Result: = '' ELSE
Begin
P: = POINTER (PATH);
INC (P, L - 1);
IF P ^ = Pathsep Then
Result: = PATH ELSE
Result: = PATH PATHSEP;
END;
END;
Procedure PATHENSURESUFFIX (VAR PATH: STRING; const pathsep: char)
Begin
PATH: = PathinClsuffix (path, patsep);
END;
Procedure Pathensurenosuffix (var path: string; const pathsep: char);
Begin
PATH: = PATHEXCLSUFFIX (PATH, PATHSEP);
END;
Function PatHexclsuffix (const path: string; const pathsep: char): String;
Var l: integer;
P: pchar;
Begin
L: = Length (path);
IF l = 0 THEN
Result: = '' Elsebegin
P: = POINTER (PATH);
INC (P, L - 1);
IF P ^ = Pathsep Then
Result: = COPY (Path, 1, L - 1) ELSE
Result: = PATH;
END;
END;
Function Pathcanonical (const path: string; const pathsep: char): String;
Var L, M: integer;
I, J: Integer;
P: stringArray;
Q: PCHAR;
Begin
Result: = PATH;
// /./ References
M: = Length (Result);
Repeat
L: = m;
IF l = 0 THEN
EXIT;
Result: = Strreplace ('/./', '/', result);
Result: = Strreplace ('/./', '/', result);
M: = Length (Result);
Until L = M;
// ./ prefix
Strensurenoprefix (Result, './');
Strensurenoprefix (Result, './');
// /. SUFFIX
Strensurenosuffix (Result, '/.');
Strensurenosuffix (Result, '/.');
// ..
IF POS ('..', result)> 0 THEN
Begin
P: = strsplitchar (result, patsep);
Repeat
J: = -1;
For i: = length (p) - 1 Downto 0 DO
IF p [i] = '..' Then
Begin
J: = i;
Break;
END;
IF j = -1 Then
Break;
M: = -1;
For i: = j - 1 Downto 0 DO
IF (p [i] = '') or (i = 0) and pathhasdriveletter (p [i])) THEN
Break else
IF P [i] <> '..' Then
Begin
M: = i;
Break;
END;
IF m = -1 Then
Break;
REMOVE (P, J, 1);
REMOVE (P, M, 1);
Until false;
Result: = StrjoinChar (p, pathsep);
END;
// /../ prefix
While strmatchLeft (result, '/../') DO
DELETE (Result, 1, 3);
While strmatchLeft (result, '/../') DO
DELETE (Result, 1, 3);
if (Result = '/ ..') or (Result = '/ ..').
Result: = '';
L: = longth (result);
IF l = 0 THEN
EXIT;
// x: /../ prefix
Q: = POINTER (Result);
IF Q ^ in ['a' .. 'z', 'a' .. 'z'] thenbegin
IF strmatch (result, ': /../', 2) THEN
Delete (Result, 4, 3) Else
IF (l = 5) and strmatch (result, ': / ..', 2).
Begin
SETLENGTH (RESULT, 2);
EXIT;
END;
L: = longth (result);
END;
// Single Dot
Q: = POINTER (Result);
IF l = 1 THEN
Begin
IF Q ^ = '.' Then
Result: = '';
EXIT;
END;
// final dot
INC (q, l - 2);
IF not (q ^ in ['.', '/', '/', ':']) THEN
Begin
INC;
IF Q ^ = '.' Then
DELETE (Result, L, 1);
END;
END;
Function PATHEXPAND (Const Path: String;
Const pathsep: char): string;
Begin
IF path = '' THEN
Result: = Basepath Else
IF Pathisabsolute (PATH) THEN
Result: = PATH ELSE
Result: = pathinclsuffix (basepath, patsep) path;
Result: = pathcanonical (Result, Pathsep);
END;
Function PathlefTelement (const path: string; const pathsep: char): string;
VAR i: integer;
Begin
I: = poschar (patsep, path);
IF i <= 0 THEN
Result: = PATH ELSE
Result: = COPY (Path, 1, I - 1);
END;
Procedure PathSplitlefTelement (const path: string) (CONST PATH: STRIN)
Var Leftelement, RightPath: String; const pathsep: char);
VAR i: integer;
Begin
I: = poschar (patsep, path);
IF i <= 0 THEN
Begin
LeftElement: = path;
Rightpath: = '';
END ELSE
Begin
LeftElement: = Copy (Path, 1, I - 1);
Rightpath: = CopyFrom (Path, i 1);
END;
END;
Procedure DecodefilePath (const filepath: string; var path, filename: string;
Const Pathsep: char);
VAR i: integer;
Begin
I: = POSCHARREV (Pathsep, FilePath);
IF i <= 0 THEN
Begin
PATH: = ''; filename: = filepath;
END ELSE
Begin
PATH: = Copy (FilePath, 1, i);
FileName: = CopyFrom (FilePath, i 1);
END;
END;
Function FileNameValid (const filename: string): String;
Begin
Result: = strreplacechar (['/', '/', ':', '>', '<', '*', '?'], '_', Filename);
if Result = '.' Then
Result: = '' ELSE
If result = '..' Then
Result: = '_';
END;
Function Filepath (Const FileName, Path: String; Const Basepath: String;
Const pathsep: char): string;
VAR P, F: String;
Begin
F: = filenamevalid (filename);
IF f = '' Then
Begin
Result: = '';
EXIT;
END;
P: = PATHEXPAND (Path, BasePath, Pathsep);
IF P = '' THEN
Result: = f Else
Result: = Pathinclsuffix (p, patsep) f;
END;
Function DirectoryExpand (Const Path: String;
Const pathsep: char): string;
Begin
Result: = PATHEXPAND (PathinClsuffix (Path, Pathsep),
Pathinclsuffix (BasePath), Pathsep;
END;
Function UNIXPathtowinPath (const path: string): String;
Begin
Result: = StrreplaceChar ('/', '/',
StrreplaceChar (['/', ':', '<', '>', '|'], '_', path);
END;
Function WinPathTounixPath (const path: string): String;
Begin
Result: = PATH;
IF pathhasdriveletter (path) THEN
Begin
// x: -> / x
Result [2]: = Result [1];
Result [1]: = '/';
END ELSE
IF strmatchleft (path, '//./') THEN
// // -> /
Delete (Result, 1, 3) Else
If Pathisuncpath (PATH) THEN
/ // -> /
DELETE (Result, 1, 1);
Result: = strreplacechar ('/', '/', strreplacechar (['/', ':', '<', '>', '|'], '_', result);
END;
{}
{File Operations}
{}
Function GetFileSize (const filename: string): int64;
VAR SREC: TSEARCHREC;
Begin
IF Findfirst (FileName, Faanyfile, SREC) <> 0 THEN
Result: = -1 else
Begin
{$ IFDEF OS_MSWIN}
{$ WARNINGS OFF}
INT64REC (Result) .lo: = SREC.FINDDATA.NFILESZELOW;
INT64REC (Result) .hi: = SREC.Finddata.nFileSizeHigh;
{$ Ifdef debug} {$ warnings on} {$ ENDIF}
{$ Else}
Result: = SREC.SIZE;
{$ ENDIF}
FindClose (SREC);
END;
END;
Function GetFileDateTime (const filename: string): tdatetime;
VAR AGE: Longint
Begin
Age: = fileage (filename);
IF agn = -1 Then
Result: = 0
Else
Result: = FileDateTodateTime (AGE);
END;
Function GetFirstFileNameMatch (const filemask: string): String;
VAR SREC: TSEARCHREC;
Begin
Result: = '';
IF Findfirst (Filemask, Faanyfile, SREC) = 0 THEN
Try
Repeat
If SREC.ATR AND FADIRECTORY = 0 THEN
Begin
Result: = extractfilepath (filemask) SREC.NAME;
EXIT;
END;
Until FindNext (SREC) <> 0;
Finally
FindClose (SREC);
END;
END;
Function DirentrygetTR (const filename: string): integer;
VAR SREC: TSEARCHREC;
Begin
IF (filename = '') or pathiSdriveletter (filename) THEN
Result: = -1 else
IF pathisroot (filename) THEN
Result: = $ 0800 or Fadirectory Else
IF Findfirst (PatHexclsuffix (Filename, '/'), Faanyfile, SREC) = 0 THENBEGIN
Result: = SREC.ATTR;
FindClose (SREC);
end
Else
RESULT: = -1;
END;
Function DirentryiSdirectory (const filename: string): boolean;
VAR SREC: TSEARCHREC;
Begin
IF (filename = '') or pathiSdriveletter (filename) THEN
Result: = FALSE ELSE
IF pathisroot (filename) THEN
Result: = True Else
IF Findfirst (PatHexclsuffix (Filename, '/'), Fadirectory, SREC) = 0 THEN
Begin
Result: = SREC.ATTR AND FADIRECTORY <> 0;
FindClose (SREC);
end
Else
Result: = FALSE;
END;
{$ IFDEF DELPHI6_UP} {$ WARN SYMBOL_PLATFORM OFF} {$ ENDIF}
Function FileHasattr (Const FileName: String; Const Attr: Word): Boolean
VAR A: Integer;
Begin
A: = filegetattr (filename);
Result: = (a> = 0) AND (a and attr <> 0);
END;
Function FileisreadOnly (const filename: string): boolean;
Begin
Result: = FileHasattr (FileName, FareadOnly);
END;
Procedure Copyfile (Const filename); Destname: String
VAR
CopyBuffer;
BYTESCOPIED: Longint;
Source, DEST: Integer;
Destination: tfilename;
Const
CHUNKSIZE = 8192;
Begin
Destination: = ExpandFileName (Destname);
If FileHasattr (Destination, Fadirectory) THEN/ if Destination is A Directory, Append File Name
Destination: = destination '/' extractfilename (filename);
GetMem (CopyBuffer, Chunksize);
Try
Source: = FileOpen (FileName, FMSharedenywrite);
IF Source <0 THEN
Raise EfileError.createfmt ('Can Not Open File% S', [FileName]);
Try
DEST: = FileCreate (Destination);
IF dest <0 THEN
Raise EfileError.createfmt ('Can Not Create File% S', [Destination]);
Try
REPEATBYTESCOPIED: = fileRead (Source, CopyBuffer ^, Chunksize);
IF BYTESCOPIED> 0 THEN
FileWrite (DEST, COPYBUFFER ^, BYTESCOPIED);
Until bytescopied Finally FileClose (DEST); END; Finally FileClose (Source); END; Finally Freemem (CopyBuffer, Chunksize); END; END; Procedure Movefile (Const filename); Destname: String VAR DESTINATION: STRINATION; Attr: integer; Begin Destination: = ExpandFileName (Destname); IF not renamefile (filename, destination) THEN Begin Attr: = filegetattr (filename); IF (Attr And Fareadonly <> 0). Raise EfileError.create (Format ('can not move file% s', [filename]); CopyFile (filename, destination); Deletefile (filename); END; END; Function deletefiles (const filemask: string): boolean; VAR SREC: TSEARCHREC; PATH: STRING; Begin Result: = Findfirst (Filemask, Faanyfile, SREC) = 0; IF NOT RESULT THEN EXIT; Try PATH: = ExtractFilePath (filemask); Repeat IF (SREC.NAME <> ') AND (SREC.NAME <>'. ') and (SREC.NAME <>' .. ') and (SREC.ATR AND (FAVOLUMEID FADIRECTORY) = 0) THEN Begin Result: = deletefile (Path SRec.name); IF NOT RESULT THEN Break; END; Until FindNext (SREC) <> 0; Finally FindClose (SREC); END; END; {$ IFDEF DELPHI6_UP} {$ WARN SYMBOL_PLATFORM ON} {$ ENDIF} {$ IFDEF OS_MSWIN} {} {Logical Drive functions} {} Function DriveiSvalid (const drive: char): boolean; VAR D: char; Begin D: = Upcase (Drive); Result: = D in ['a' .. 'z']; if not result the EXIT; Result: = ISBITSET (GetLogicalDrives, ORD (D) - ORD ('A')); END; Function DrivegetType (const path: string): TLOGICALDRIVETYPE; Begin Case GetDriveType (Pchar (PATH)) of Drive_removable: Result: = driveremovable; Drive_fixed: result: = drivefixed; Drive_remote: result: = driveremote; Drive_cdrom: result: = drivecdrom Drive_ramdisk: result: = driveramdisk; Else RESULT: = drivetypeunknown; END; END; Function DriveFreespace (const path: string): int64; VAR D: BYTE; Begin IF pathhasdriveletter (path) THEN D: = ORD (UpCase (PCHAR (PCHAR (PCHAR (PATH) ^) - ORD ('A') 1 ELSE If Pathisuncpath (PATH) THEN Begin RESULT: = -1; EXIT; END ELSE D: = 0; Result: = DiskFree (D); END; {$ ENDIF} {} {Self-testing code} {} {$ Assertions on} Procedure Selftest; Begin ASSERT (PathhasDriveletter ('C:'), 'PathhasDriveletter'; ASSERT ('c: /'), 'PathhasDriveletter'; ASSERT (NOT PATHHASDRIVELETER ('/ c /'), 'pathhasdriveletter'; Assert (NOT PATHHASDRIVELETER ('::'), 'PathhasDriveletter'; Assert (Pathisabsolute ('/'), 'Pathisabsolute'; Assert (Pathisabsolute ('/ c'), 'Pathisabsolute'; Assert (Pathisabsolute ('/ c /'), 'Pathisabsolute'; Assert (Pathisabsolute ('C: /'), 'Pathisabsolute'; Assert (Pathisabsolute ('c:'), 'Pathisabsolute'); Assert (Pathisabsolute ('/ c / "),' Pathisabsolute '); ASSERT (NOT Pathisabsolute (''), 'Pathisabsolute'; ASSERT (NOT Pathisabsolute ('c'), 'Pathisabsolute'; Assert (NOT Pathisabsolute ('c /'), 'Pathisabsolute'; ASSERT (NOT Pathisabsolute ('C / D'), 'Pathisabsolute'; ASSERT (NOT Pathisabsolute ('C / D /'), 'Pathisabsolute'; Assert ('../'), 'pathisabsolute'; Assert ('/'), 'PathiSdirectory'; Assert ('/ c /'), 'PathiSDirectory'); ASSERT ('c:'), 'PathiSDirectory'; ASSERT (PathisDirectory); 'PathiSDirectory'; ASSERT ('c: / d /'), 'PathiSdirectory'; ASSERT ('),' PathiSDirectory '; ASSERT ('D'), 'PathiSDirectory'; ASSERT (NOT PathisDirectory); 'PathiSDirectory'; Assert (',' / ') =' ',' PathinClsuffix '; Assert (PathinClsuffix ('c', '/') = 'c /', 'PathinClsuffix'; Assert (Pathinclsuffix ('c /', '/') = 'c /', 'PathinClsuffix'; Assert (PathinClsuffix ('C / D', '/') = 'c / d /', 'PathinClsuffix'; Assert (PathinClsuffix ('c / d /', '/') = 'c / d /', 'Pathinclsuffix'; ASSERT (PathinClsuffix ('c:', '/') = 'c: /', 'PathinClsuffix'); Assert (PathinClsuffix ('c: /', '/') = 'c: /', 'Pathinclsuffix'); assert (PatHexclsuffix ('', '/') = '', 'PatHexclsuffix'); ASSERT (PATHEXCLSUFFIX ('c', '/') = 'c', 'PatHexclsuffix'; Assert ('c /', '/') = 'c', 'PatHexclsuffix'; Assert (PATHEXCLSUFFIX ('c / d', '/') = 'c / d', 'PatHEXclsuffix'; Assert (PATHEXCLSUFFIX ('c / d /', '/') = 'c / d', 'PatHexclsuffix'); Assert (PATHEXCLSUFFIX ('c:', '/') = 'c:', 'PatHexclsuffix'; Assert (PATHEXCLSUFFIX ('c: /', '/') = 'c:', 'patrhexclsuffix'); Assert ('', '/') = '', 'Pathcanonical'); Assert ('.', '/') = ',' Pathcanonical '); Assert ('./', '/') = ',' Pathcanonical '); Assert ('./', '/') = '../', 'Pathcanonical'); Assert (Pathcanonical ('/../', '/') = '/', 'pathcanonical'; Assert ('/ x /../../', '/') = '/', 'Pathcanonical'); Assert ('/ ..', '/') = ',' Pathcanonical '); Assert (Pathcanonical ('x', '/') = 'x', 'Pathcanonical'); Assert ('/ x', '/') = '/ x', 'Pathcanonical'; ASSERT (Pathcanonical ('x.', '/') = 'X', 'Pathcanonical'; Assert ('.', '/') = '', 'Pathcanonical'); Assert ('/ x.', '/') = '/ X', 'Pathcanonical'; Assert ('/ x.y', '/') = '/X.y', 'Pathcanonical'); Assert ('/ x.y /', '/') = '/X.Y/', 'Pathcanonical'); Assert ('/ a / x..y /', '/') = '/a/x..y/', 'Pathcanonical'); ASSERT ('/ a/ .y /', '/') = '/A/.y/', 'Pathcanonical'); Assert ('/ a/ .. y /', '/') = '/a/..y', 'Pathcanonical'); Assert ('/ a / y ../', '/') = '/a/y../', 'pathcanonical'); Assert ('/ a / y ..', '/') = '/ a / y ..', 'Pathcanonical'); Assert (Pathcanonical ('x', '/') = 'x', 'Pathcanonical'); Assert ('x /', '/') = 'x /', 'Pathcanonical'); Assert (Pathcanonical ('x / y / ..', '/') = 'x', 'Pathcanonical'); Assert ('x / y / ",' / ') =' x / ',' pathcanonical '); Assert ('/ x / y / ..', '/') = '/ x', 'Pathcanonical'); Assert ('/ x / y / ",' / ') =' / x / ',' Pathcanonical '); Assert ('/ x / y / "(') = '', 'Pathcanonical'); Assert (Pathcanonical ('/ x / y / ") =' / ',' Pathcanonical '); Assert (Pathcanonical ('/ A /././', '/') = '/ a /', 'Pathcanonical'); Assert (Pathcanonical 'C:', '/') = 'c:', 'Pathcanonical'; Assert (Pathcanonical ('c: /', '/') = 'c: /', 'Pathcanonical'; Assert (Pathcanonical ('C: / A / ..', '/') = 'c:', 'Pathcanonical'); Assert (Pathcanonical ('c: / a /../', '/') = 'c: /', 'pathcanonical'); Assert (Pathcanonical ('c: /../', '/') = 'c: /', 'Pathcanonical'); Assert (Pathcanonical ('c: / ..', '/') = 'c:', 'Pathcanonical'); Assert (Pathcanonical ('c: / a / hwan/ ..', '/') = 'c:', 'Pathcanonical'); Assert ('c: / a /../../', '/') = 'c: /', 'Pathcanonical'); ASSERT (Pathcanonical ('/ a / b / m/ c / d / ",' / ') =' / a / c / ',' Pathcanonical '); ASSERT (Pathcanonical ('/ a / b / m/', '/') = '/ a /', 'pathcanonical'); Assert (Pathcanonical ('/ a / b / m ...,' / ') =' / ',' Pathcanonical '); Assert ('/ a / b / h ... /../../../../', '/') = '/', 'Pathcanonical'); Assert ('', ',' / ') =', 'PatHexpand'); Assert ('', '/', '/') = '/', 'PATHEXPAND'); Assert ('', ',' / c ',' / ') =' / c ',' PatHexpand '; Assert ('', '/ c /', '/') = '/ c /', 'PATHEXPAND'); assert ('../', '/ c /', '/') = '/', 'PatHexpand'); Assert ('..', '/ c /', '/') = '', 'PATHEXPAND'); Assert ('/ ..', '/ c /', '/') = '', 'PATHEXPAND'); Assert ('/../', '/ c /', '/') = '/', 'PATHEXPAND'); Assert ('a', '../', '/') = '../a', 'PatHexpand'); Assert ('../', '../', '/') = '../../', 'PatHexpand'); Assert ('/', '', '/') = '/', 'PATHEXPAND'); Assert ('/', '/ c', '/') = '/', 'PATHEXPAND'); Assert ('/ a', '/ c /', '/') = '/ a', 'PatHexpand'); Assert ('/ a /', '/ c /', '/') = '/ a /', 'patrolpand'); Assert ('/ a / b', '/ c', '/') = '/ a / b', 'PatHexpand'); Assert ('A / B', '/ C', '/') = '/ c / a / b', 'PatHexpand'); Assert ('A / B', '/ C', '/') = '/ c / a / b', 'PatHexpand'); Assert ('a / b', '/ c /', '/') = '/ c / a / b', 'PatHexpand'); Assert ('a / b', '/ c /', '/') = '/ c / a / b', 'PatHexpand'); Assert (PatHexpand ('A / B', 'C / D', '/') = 'c / d / a / b', 'PatHexpand'); Assert ('../ A / B', ' C / D ',' / ') =' c / a / b ',' PATHEXPAND '); Assert ('../ A / b', '/ c / d', '/') = '/ c / a / b', 'PatHexpand'); Assert ('./../ b', 'c / d', '/') = 'A / b', 'PATHEXPAND'); Assert ('../../ b', '/ c / d', '/') = '/ a / b', 'PatHexpand'); Assert ('../../../ A / b', '/ c / d', '/') = '/ a / b', 'PATHEXPAND'); Assert ('/../ / b', '/ c / d', '/') = '/ a / b', 'PATHEXPAND'); Assert ('../ a / b', '/../c/d', '/') = '/ c / a / b', 'PatHexpand'); Assert ('../ A / b', '../c/d', '/') = '../c/a/b', 'PatHexpand'); Assert ('../ a / b', 'c: / c / d', '/') = 'c: / c / a / b', 'PatHexpand'); Assert ('../ A / b /', 'c: / c / d', '/') = 'c: / c / a / b /', 'patrolpand'); Assert (FilePath ('c', '../x/y', 'a / b', '/') = 'A / X / Y / C', 'FilePath'); Assert (FilePath ('c', '/ x / y', 'A / b', '/') = '/ x / y / c', 'filepath'); Assert (FilePath ('C', '', 'A / B', '/') = 'A / B / C', 'FilePath'; Assert (FilePath ('', '/ x / y', 'A / b', '/') = ',' filepath '); Assert (FilePath ('C', 'X / Y', 'A / B', '/') = 'A / B / X / Y / C', 'FilePath'); Assert (FilePath ('C', 'X / y', '', '/') = 'x / y / c', 'filepath'); Assert (',', ',' / ') =', 'DirectoryExpand'); Assert ('', ',' / x ',' / ') =' / x / ',' DirectoryExpand '; Assert (DirectoryExpand ('/', '/ x', '/') = '/', 'DirectoryExpand'); Assert ('/ a', '/ x', '/') = '/ a /', 'DirectoryExpand'; Assert (DirectoryExpand ('/ A /', '/ x', '/') = '/ a /', 'DirectoryExpand'); Assert (DirectoryExpand ('/ A / b', '/ x', '/') = '/ a / b /', 'DirectoryExpand'; Assert (DirectoryExpand ('a', '/ x', '/') = '/ x / a /', 'DirectoryExpand'); Assert (DirectoryExpand ('A /', '/ x', '/') = '/ x / a /', 'DirectoryExpand'); Assert (DirectoryExpand ('c:', '/ x', '/') = 'c: /', 'DirectoryExpand'); Assert ('c: /', '/ x', '/') = 'c: /', 'DirectoryExpand'); Assert (UnixPathtowinPath ('/ c / d.f') = '/c/d.f', 'UnixPathtowinPath'; AssertH ('/ c / d.f') = '/ C/d.f', 'WinPathTounixPath'; END; End.