home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 April A / Pcwk4a98.iso / PROGRAM / DELPHI16 / Calmira / Src / UTILS / FILES.PAS < prev    next >
Pascal/Delphi Source File  |  1997-02-15  |  11KB  |  388 lines

  1. {*********************************************************}
  2. {                                                         }
  3. {    Calmira System Library 1.0                           }
  4. {    by Li-Hsin Huang,                                    }
  5. {    released into the public domain January 1997         }
  6. {                                                         }
  7. {*********************************************************}
  8.  
  9. unit Files;
  10.  
  11. { Medium level file utilities }
  12.  
  13. interface
  14.  
  15. uses Classes, WinTypes, SysUtils;
  16.  
  17. type
  18.   TDirInfo = record
  19.     files : Integer;
  20.     dirs  : Integer;
  21.     size  : Longint;
  22.   end;
  23.  
  24.   TDropInfo = record
  25.     files : TStringList;
  26.     posn  : TPoint;
  27.   end;
  28.  
  29.   EFileIOError = class(Exception);
  30.  
  31.   EFileMoveError = class(EFileIOError);
  32.   EInsufficientSpace = class(EFileIOError);
  33.  
  34.   EFileNotFound = class(EFileIOError);
  35.   EPathNotFound = class(EFileIOError);
  36.   EAccessDenied = class(EFileIOError);
  37.  
  38.   EReadAccessDenied = class(EAccessDenied);
  39.   EWriteAccessDenied = class(EAccessDenied);
  40.  
  41.   EReadFileNotFound = class(EFileNotFound);
  42.   EWriteFileNotFound = class(EFileNotFound);
  43.  
  44.   EReadPathNotFound = class(EPathNotFound);
  45.   EWritePathNotFound = class(EPathNotFound);
  46.  
  47.  
  48. procedure FindFiles(const FileSpec : TFilename; attrib : Word; List: TStrings);
  49. { Executes a FindFirst/FindNext loop using the given file specifications.
  50.   The search results are added to the strings object }
  51.  
  52. function DirInfo(const Dirname: TFilename; Subs : Boolean) : TDirInfo;
  53. { Returns a record giving information about the specified directory.
  54.   If Subs is True, this information includes details taken from
  55.   subdirectories. }
  56.  
  57. function FFileExists(const Filename: TFilename): Boolean;
  58. function FFileCreate(const Filename: TFilename): Integer;
  59. function FFileOpen(const Filename: TFilename; mode: word): Integer;
  60. function FDirectoryExists(const Filename: TFilename): Boolean;
  61. { These functions perform the same tasks as those without the
  62.   F prefix but raise an EPathNotFound exception if the parent
  63.   directory doesn't exist.  Typically, this catches situations when a
  64.   floppy disk is not in the drive }
  65.  
  66. function HDirectoryExists(const Filename: TFilename): Boolean;
  67. { Same as DirectoryExists in FileCtrl except that hidden ones are detected }
  68.  
  69. function FCopyFile(const Filename, Destname : TFilename): Longint;
  70. { Copies any file while preserving the attributes and DOS timestamp.
  71.   If there is not enough room on the destination disk, EInsufficientSpace
  72.   is raised and if the destination has been created then it is deleted. }
  73.  
  74. procedure FMoveFile(const Filename, Destname : TFilename);
  75. { Moves a file, first by attempting a rename (which is fast), and
  76.   then by copying the file and deleting the original }
  77.  
  78. function ExecuteFile(const FileName, Params, DefaultDir: string;
  79.   Op: PChar; ShowCmd: Word): THandle;
  80. { Encapsulates the API ShellExecute function using Pascal strings }
  81.  
  82. function RandomFilename(const path, prefix, ext: TFilename): TFilename;
  83. { Generates a random filename in the given path (you must add
  84.   a trailing backslash), which does not already exist.  The prefix
  85.   can be up to 4 characters and the extension is optional.
  86.  
  87.   For example, RandomFilename('c:\temp\', 'abcd', 'txt') will
  88.   return filenames like 'abcd4723.txt' }
  89.  
  90. function IsAncestorDir(const parent, child: TFilename): Boolean;
  91. { Returns True if the first parameter is an an ancestor directory
  92.   of the second parameter.  This function just analyses the strings,
  93.   and doesn't check the disk. }
  94.  
  95. function IsValidFilename(const s: TFilename): Boolean;
  96. { Returns True if the string is a valid 8.3 character MS-DOS filename }
  97.  
  98. function WildcardMatch(const filename, wildcard: string): Boolean;
  99. { Returns True if the filename is specified by the wildcard }
  100.  
  101. function ShowCmdsEx(n : Integer): Word;
  102. { Converts and integer into a ShowWindow command.  Returns SW_SHOWMINNOACTIVE
  103.   if the parameter is 1, SW_SHOWMAXIMIZED if the parameter is 2, and
  104.   SW_SHOWNORMAL otherwise.  Use it with ExecuteFile and similar commands }
  105.  
  106. function QualifiedFilename(const s: TFilename) : TFilename;
  107.  
  108. const
  109.   { Use this to convert a "ShowMinimized" variable into a command }
  110.   ShowCmds : array[Boolean] of Word = (SW_SHOWNORMAL, SW_SHOWMINNOACTIVE);
  111.  
  112.   BackgroundProc : procedure = nil;
  113.  
  114. implementation
  115.  
  116. uses ShellAPI;
  117.  
  118.  
  119. procedure FindFiles(const Filespec : TFilename; attrib : Word; List : TStrings);
  120. var
  121.   rec : TSearchRec;
  122.   code : Integer;
  123. begin
  124.   code := FindFirst(Filespec, attrib, rec);
  125.   while code = 0 do begin
  126.     List.Add(rec.name);
  127.     code := FindNext(rec);
  128.   end;
  129. end;
  130.  
  131.  
  132.  
  133. function FFileCreate(const Filename: TFilename): Integer;
  134. var s: string;
  135. begin
  136.   Result := FileCreate(Filename);
  137.   if Result < 0 then begin
  138.     s := 'Cannot create ' + Filename;
  139.     case Result of
  140.     -5 : raise EWriteAccessDenied.Create('Access denied. ' + s);
  141.     -3 : raise EWritePathNotFound.Create('Path not found. ' + s);
  142.     else raise EFCreateError.Create(s);
  143.     end;
  144.   end;
  145. end;
  146.  
  147.  
  148. function FFileOpen(const Filename: TFilename; mode: word): Integer;
  149. var s: string;
  150. begin
  151.   Result := FileOpen(Filename, mode);
  152.   if Result < 0 then begin
  153.     s := 'Cannot open ' + Filename;
  154.     case Result of
  155.     -5 : raise EReadAccessDenied.Create('Access denied. ' + s);
  156.     -3 : raise EReadPathNotFound.Create('Path not found. ' + s);
  157.     -2 : raise EReadFileNotFound.Create('File not found. ' + s);
  158.     else raise EFOpenError.Create(s);
  159.     end;
  160.   end;
  161. end;
  162.  
  163.  
  164. function FFileExists(const Filename: TFilename): Boolean;
  165. var
  166.   rec: TSearchRec;
  167.   code: Integer;
  168. begin
  169.   code := FindFirst(Filename,
  170.     faAnyFile and not (faVolumeID or faDirectory), rec);
  171.  
  172.   if code = -3 then
  173.     raise EPathNotFound.CreateFmt('Path %s not found.', [ExtractFilePath(Filename)])
  174.   else
  175.     Result := code = 0;
  176. end;
  177.  
  178.  
  179. function FDirectoryExists(const Filename: TFilename): Boolean;
  180. var
  181.   rec: TSearchRec;
  182.   code: Integer;
  183. begin
  184.   code := FindFirst(Filename,
  185.     faDirectory or faHidden or faSysFile or faReadOnly, rec);
  186.  
  187.   if code = -3 then
  188.     raise EPathNotFound.CreateFmt('Path %s not found.', [ExtractFilePath(Filename)])
  189.   else
  190.     Result := code = 0;
  191. end;
  192.  
  193.  
  194. function HDirectoryExists(const Filename: TFilename): Boolean;
  195. var rec : TSearchRec;
  196. begin
  197.   Result := FindFirst(Filename,
  198.     faDirectory or faHidden or faSysFile or faReadOnly, rec) = 0;
  199. end;
  200.  
  201.  
  202. function FCopyFile(const Filename, Destname : TFilename): Longint;
  203. const CopyBufSize : Word = 8192;
  204. var
  205.   source, dest, attr: Integer;
  206.   Bytes, TimeStamp: Longint;
  207.   success : Boolean;
  208.   CopyBuf : Pointer;
  209. begin
  210.   Result := 0;
  211.   attr := FileGetAttr(Filename);
  212.  
  213.   source := FFileOpen(Filename, fmShareDenyWrite);
  214.   try
  215.     success := False;
  216.     TimeStamp := FileGetDate(source);
  217.     dest   := FFileCreate(Destname);
  218.     try
  219.       Getmem(CopyBuf, CopyBufSize);
  220.       try
  221.         repeat
  222.           Bytes := FileRead(Source, CopyBuf^, CopyBufSize);
  223.           Inc(Result, Bytes);
  224.           if (Bytes > 0) and (FileWrite(Dest, CopyBuf^, Bytes) <> Bytes) then
  225.             raise EInsufficientSpace.CreateFmt(
  226.               'Insufficient disk space to copy %s to %s', [Filename, Destname]);
  227.           if Assigned(BackgroundProc) then BackgroundProc;
  228.         until Bytes < CopyBufSize;
  229.         success := True;
  230.       finally
  231.         Freemem(CopyBuf, CopyBufSize);
  232.       end;
  233.     finally
  234.       if Success then begin
  235.         FileSetDate(dest, TimeStamp);
  236.         if attr <> faArchive then FileSetAttr(Destname, attr);
  237.       end;
  238.       FileClose(dest);
  239.       if not Success then DeleteFile(Destname);
  240.     end;
  241.   finally
  242.     FileClose(source);
  243.   end;
  244. end;
  245.  
  246.  
  247.  
  248. procedure FMoveFile(const Filename, Destname : TFilename);
  249. begin
  250.   if not RenameFile(FileName, Destname) then
  251.   begin
  252.     if FileGetAttr(FileName) and faReadOnly = faReadOnly then
  253.       raise EFileMoveError.Create('Cannot move ' + FileName);
  254.     FCopyFile(FileName, Destname);
  255.     if not DeleteFile(FileName) then begin
  256.       FileSetAttr(Destname, 0);
  257.       DeleteFile(Destname);
  258.       raise EFileMoveError.Create('Cannot move ' + Filename);
  259.     end;
  260.   end;
  261. end;
  262.  
  263.  
  264.  
  265. function ExecuteFile(const FileName, Params, DefaultDir: string;
  266.   Op: PChar; ShowCmd: Word): THandle;
  267. var
  268.   zFileName, zParams, zDir: array[0..255] of Char;
  269. begin
  270.   Result := ShellExecute(0, Op,
  271.     StrPCopy(zFileName, FileName), StrPCopy(zParams, Params),
  272.     StrPCopy(zDir, DefaultDir), ShowCmd);
  273. end;
  274.  
  275.  
  276. function DirInfo(const Dirname: TFilename; Subs : Boolean) : TDirInfo;
  277. var
  278.   rec : TSearchRec;
  279.   code : Integer;
  280. begin
  281.   Result.files := 0;
  282.   Result.dirs := 0;
  283.   Result.size := 0;
  284.  
  285.   code := FindFirst(Dirname + '\*.*', faAnyfile and not faVolumeID, rec);
  286.   while code = 0 do begin
  287.     Inc(Result.size, rec.size);
  288.     if rec.attr and faDirectory <> 0 then begin
  289.       if rec.name[1] <> '.' then begin
  290.         Inc(Result.dirs);
  291.         if Subs then with DirInfo(Dirname + '\' + rec.name, true) do begin
  292.           Inc(Result.files, files);
  293.           Inc(Result.dirs, dirs);
  294.           Inc(Result.size, size);
  295.         end;
  296.       end
  297.     end
  298.     else Inc(Result.files);
  299.     code := FindNext(rec);
  300.   end;
  301. end;
  302.  
  303.  
  304. function RandomFilename(const path, prefix, ext: TFilename): TFilename;
  305. var
  306.   i: Integer;
  307. begin
  308.   i := Random(10000);
  309.   repeat
  310.     Inc(i);
  311.     Result := Format('%s%.4s%d%s', [path, prefix, i, ext]);
  312.   until not FileExists(Result);
  313. end;
  314.  
  315.  
  316. function IsAncestorDir(const parent, child: TFilename): Boolean;
  317. begin
  318.   if (child[0] <= parent[0]) or (child[1] <> parent[1]) then
  319.     Result := False
  320.   else
  321.     Result := (parent[0] = #3) or (Pos(parent + '\', child) = 1);
  322. end;
  323.  
  324.  
  325.  
  326. function IsValidFilename(const s: TFilename): Boolean;
  327. var
  328.   i : Integer;
  329.   seendot : Boolean;
  330. begin
  331.   i := 1;
  332.   Result := Length(s) <= 12;
  333.   seendot := False;
  334.   while (i <= Length(s)) and Result do begin
  335.     if s[i] = '.' then begin
  336.       Result := not seendot and (i <= 9) and (Length(s) - i <= 3);
  337.       seendot := True;
  338.     end
  339.     else
  340.       Result := not (s[i] in ['"', '/', '\', ':', ';', '|', '=', ',']);
  341.     Inc(i);
  342.   end;
  343.   Result := Result and (seendot or (Length(s) <= 8));
  344. end;
  345.  
  346.  
  347. function ShowCmdsEx(n : Integer): Word;
  348. begin
  349.   if n = 1 then Result := SW_SHOWMINNOACTIVE
  350.   else if n = 2 then Result := SW_SHOWMAXIMIZED
  351.   else Result := SW_SHOWNORMAL;
  352. end;
  353.  
  354. function QualifiedFilename(const s: TFilename) : TFilename;
  355. begin
  356.   Result := s;
  357.   if ExtractFileExt(Result) = '' then AppendStr(Result, '.');
  358. end;
  359.  
  360. function WildcardMatch(const filename, wildcard: string): Boolean;
  361. var i, j: Integer;
  362. begin
  363.   i := 1;
  364.   j := 1;
  365.   while (i <= Length(filename)) and (j <= Length(wildcard)) and Result do begin
  366.     case wildcard[j] of
  367.       '?' : begin
  368.               Result := filename[i] <> '.';
  369.               Inc(i);
  370.               Inc(j);
  371.             end;
  372.       '*' : begin
  373.               while (i <= Length(filename)) and (filename[i] <> '.') do
  374.                 Inc(i);
  375.               Inc(j);
  376.             end;
  377.       else begin
  378.         Result := filename[i] = wildcard[j];
  379.         Inc(i);
  380.         Inc(j);
  381.       end;
  382.     end;
  383.   end;
  384.   Result := Result and (i = Length(filename) + 1) and (j = Length(wildcard) + 1);
  385. end;
  386.  
  387. end.
  388.