home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PDIR10.ZIP / PDIR.DOC next >
Encoding:
Text File  |  1989-08-18  |  20.4 KB  |  573 lines

  1. PDir v1.0, 18 Aug 89
  2.  
  3. Palcic Directory Routines
  4. -------------------------
  5.  
  6. Matthew J. Palcic
  7. MJP Enterprises
  8. 1030 Dayton-Yellow Springs Rd.
  9. Xenia, OH  45385-9508
  10.  
  11.      The routines in PDir are Copyright (C) 1989 by Matthew J. Palcic.
  12. The code is public domain, but a donation would be greatly appreciated.
  13. Any suggestions for modifications/additions to the source code are
  14. welcome.  However, the source code is to be distributed only in its
  15. original, unmodified form.  MJP Enterprises reserves the rights to all
  16. code and documentation included with PDir.  MJP Enterprises and Matthew
  17. J. Palcic shall not be held responsible for any damages resulting from
  18. the use of this code.  No warranty is offered (express or written) for
  19. the performance or accuracy of the documentation and source code.  If
  20. you plan to use PDir for a distribution program (shareware, public
  21. domain or commercial) please inform Matthew Palcic at the address above.
  22. I'd like to know who's using my code and for what purposes.
  23.  
  24.      PDir was developed using Turbo Pascal 5.5 on a 286 machine running
  25. MS-DOS 4.01. Requires the Objects unit found on the Turbo Pascal 5.5
  26. distribution disks.
  27.  
  28.      The routines in the PDir unit are based almost entirely on the
  29. object-oriented extensions in Turbo Pascal 5.5.  The user should be
  30. familiar with the stream, node and list types found in the Objects unit
  31. provided in OOPDEMOS.ARC found on the Turbo 5.5 distribution disks. Also
  32. an understanding of recursive calls is helpful but not required to use
  33. the routines.  Even though there are many methods which may not be used
  34. in a program, the smart linker will eliminate all unused methods at
  35. compile time.  The data elements in the objects should not be directly
  36. accessed in a program; the methods defined for each object should be
  37. sufficient forms of access to the data elements.  If these routines do
  38. not fill a need, define a descendant object type that inherits all the
  39. other routines and adds the function you need.  It is strongly
  40. recommended that the user employ these objects as dynamic (using their
  41. Ptr counterparts) rather than static.  This offers much more flexibility
  42. than the static routines can offer.
  43.  
  44.      Throughout this documentation a compact notation is used to
  45. describe any elements or routines from other units.  Turbo Pascal allows
  46. a unit specifier to precede any items in the unit to prevent ambiguity
  47. (such two procedures having the same name.)
  48.  
  49.   An example:
  50.  
  51.        PDir defines a routine Rename that calls the Dos unit's routine
  52.        Rename.  Calling Rename does not clearly call either version so
  53.        PDir.Rename and Dos.Rename explicitly call one or the other.
  54.  
  55. This notation is also used to specify where a routine, variable, etc.
  56. originates.  Rather than saying 'The NameStr type found in the Dos unit'
  57. the documentation would read Dos.NameStr.  Sufficient documentation is
  58. found in the Turbo Pascal manual such that they need not be explained
  59. here.  The examples will build on other methods in the object for
  60. clarity.
  61.  
  62.  
  63. FileStr
  64. -------
  65.  
  66.      FileStr is used to combine a filename into one string rather than
  67. the separate Dos.NameStr and Dos.ExtStr.  FileStr includes the '.'
  68. before the extension.
  69.  
  70.  
  71. PDir.BaseEntry
  72. --------------
  73.  
  74.      BaseEntry is the ancestor to FileEntry and DirEntry described
  75. later.  This contains all of the information found in a Dos.SearchRec
  76. except for SearchRec.Fill.  Fill is not used by any of the routines in
  77. PDir or any other program I've seen for that matter.  The data elements
  78. contained in BaseEntry include the Name, Attribute, Size and Time
  79. (stored in standard packed format; see PackTime/UnpackTime). The
  80. function methods return the values stored in memory and may not reflect
  81. current data if the disk was updated after creating the object.
  82.  
  83.  
  84. constructor BaseEntry.Init;
  85. ---------------------------
  86.  
  87.      Dummy constructor routine meant to be overridden by descendant
  88. types.
  89.  
  90.  
  91. destructor BaseEntry.Done; virtual;
  92. -----------------------------------
  93.  
  94.      Dummy destructor routine meant to be overridden by descendant
  95. types.
  96.  
  97.  
  98. procedure BaseEntry.ConvertRec(S: SearchRec);
  99. ---------------------------------------------
  100.  
  101.      ConvertRec converts Dos.SearchRec 'S' into the data elements needed
  102. in BaseEntry.  SearchRec.Fill is ignored.
  103.  
  104.         uses Dos;
  105.         procedure GetFirstFile;
  106.           var
  107.             DirInfo: Dos.SearchRec;
  108.             FirstFile: BaseEntry;
  109.           begin
  110.           ChDir('C:\');
  111.           FirstFile.Init;  { Must call the constructor }
  112.           FindFirst('*.*',Dos.Archive,DirInfo);
  113.           FirstFile.ConvertRec(DirInfo);
  114.           ...
  115.  
  116. function BaseEntry.FileName: NameStr; virtual;
  117. ----------------------------------------------
  118.  
  119.      FileName returns the entire filename including the extension, which
  120. is often more useful than using FileName+FileExt.  This is a virtual
  121. routine, so a descendant type may define FileName to return only the
  122. filename without the extension.
  123.  
  124.          WriteLn('Filename: ',FirstFile.FileName);
  125.  
  126.      Result:
  127.          Filename: AUTOEXEC.BAT
  128.  
  129.  
  130. function BaseEntry.FileExt: ExtStr;
  131. -----------------------------------
  132.  
  133.      FileExt returns only the extension of the file, without the period.
  134. This method is virtual, so descendant types may define FileExt to
  135. include the period.
  136.  
  137.          WriteLn('Extension only: ',FirstFile.FileExt);
  138.  
  139.      Result:
  140.          Extension only: BAT
  141.  
  142.  
  143. function BaseEntry.FullName: PathStr; virtual;
  144. ----------------------------------------------
  145.  
  146.      FullName returns the same string as BaseEntry.FileName.  It is
  147. virtual so that descendant types may include a FilePath data element and
  148. define FullName to return the FilePath and FileName in one string.
  149.  
  150.  
  151. function BaseEntry.FileTime: Longint; virtual;
  152. ----------------------------------------------
  153.  
  154.      FileTime returns the file time in standard packed format (Longint).
  155. See Dos.PackTime and Dos.UnpackTime and the Dos.DateTime record.  It is
  156. virtual to allow descendant types to return current data from the disk
  157. on every call, rather than returning values stored in the object.  This
  158. would allow other routines to update a file and let FileTime return the
  159. new filetime.
  160.  
  161.           var
  162.             DT: DateTime;
  163.           begin
  164.           UnpackTime(FirstFile.FileTime,DT);
  165.           WriteLn(FirstFile.FullName);
  166.           WriteLn(Month:2,'/',Day:2,'/',(Year - 1900):2);
  167.           WriteLn(Hour:2,':',Min:2,':',Sec:2);
  168.           end;
  169.  
  170.      Result:
  171.           AUTOEXEC.BAT
  172.           11/13/88
  173.           12:35:26
  174.  
  175.  
  176. function BaseEntry.FileAttr: AttrType; virtual;
  177. -----------------------------------------------
  178.  
  179.      FileAttr returns the attribute of the file.  Constants describing
  180. the bit fields of the returned AttrType are described under 'Files,
  181. Attributes, Constants'.  This is virtual to allow real-time checking of
  182. the file attribute (especially useful for file sharing).
  183.  
  184.  
  185. function BaseEntry.FileSize: Longint; virtual;
  186. ----------------------------------------------
  187.  
  188.      FileSize returns the total size (in bytes) of the file.  This is
  189. virtual to allow the FileSize to return the current size, rather than
  190. the size in memory.
  191.  
  192. function BaseEntry.IsDirectory: Boolean;
  193. ----------------------------------------
  194.  
  195.      Returns True if the file attribute contains the Directory bit.
  196.  
  197.  
  198. constructor BaseEntry.Load(var S: Stream);
  199. ------------------------------------------
  200.  
  201.      Load will read in an object of type BaseEntry from a stream.  This
  202. is a constructor and is a suitable replacement for using BaseEntry.Init.
  203.  
  204.           var
  205.             Strm: PDir.DirStream;
  206.           begin
  207.           Strm.Init('C:\FILE.DAT',SOpen);
  208.           FirstFile.Load(Strm);
  209.           Strm.Done;
  210.           end;
  211.  
  212.  
  213. procedure BaseEntry.Store(var S: Stream); virtual;
  214. --------------------------------------------------
  215.  
  216.      Store will write the data in a BaseEntry instance to a stream.
  217.  
  218.           var
  219.             Strm: PDir.DirStream;
  220.           begin
  221.           Strm.Init('C:\FILE.DAT',SCreate);
  222.           FirstFile.Store(Strm);
  223.           Strm.Done;
  224.           end;
  225.  
  226.  
  227. PDir.FileEntry
  228. --------------
  229.  
  230.      A descendant of BaseEntry offering methods to change any of the
  231. elements in BaseEntry.  No new data elements are defined.
  232.  
  233.  
  234. constructor FileEntry.Init;
  235. ---------------------------
  236.  
  237.      Initializes the data elements to acceptable empty values to prevent
  238. impossible dates, times, filenames, etc.
  239.  
  240.  
  241. destructor FileEntry.Done; virtual;
  242. -----------------------------------
  243.  
  244.      Dummy destructor that calls BaseEntry.Done;
  245.  
  246.  
  247. procedure FileEntry.ForceExt(E:ExtStr);
  248. ---------------------------------------
  249.  
  250.      ForceExt accepts a file extension (without the period) and forces
  251. it on the filename.  This is useful for changing a .DAT file to a .BAK
  252. file, etc.  This calls Rename to change the name of the file on disk and
  253. in memory.
  254.  
  255.           ...
  256.           WriteLn('Old name: ',FileEntry.FullName);
  257.           FileEntry.ForceExt('ZIP');
  258.           WriteLn('New name: ',FileEntry.FullName);
  259.           ...
  260.  
  261.                     Old name: GARBAGE.ARC
  262.                     New name: GARBAGE.ZIP
  263.  
  264.  
  265. procedure FileEntry.ChangeName(P:PathStr); virtual;
  266. ---------------------------------------------------
  267.  
  268.      ChangeName will only change the filename in memory.  Rename should
  269. be used to change the name on disk.
  270.  
  271.  
  272. procedure FileEntry.ChangePath(P:PathStr); virtual;
  273. ---------------------------------------------------
  274.  
  275.      ChangePath performs the same function as ChangeName.  Descendant
  276. types should declare ChangePath to change the path and the filename.
  277.  
  278.  
  279. procedure FileEntry.ChangeTime(T:Longint); virtual;
  280. ---------------------------------------------------
  281.  
  282.      ChangeTime only changes the time in memory.  SetTime should be used
  283. to update the time on disk.
  284.  
  285.  
  286. procedure FileEntry.ChangeAttr(A:AttrType); virtual;
  287. ----------------------------------------------------
  288.  
  289.      ChangeAttr only changes the attribute in memory.  SetAttr should be
  290. used to change the attribute on disk.
  291.  
  292.  
  293. function FileEntry.Erase: Boolean; virtual;
  294. -----------------------------------
  295.  
  296.      Erase will remove the file from the directory.  If the file is
  297. locked or has read-only status the file will not be deleted.  Descendant
  298. types could define Erase to set the attribute to allow deletion
  299. regardless of the current attribute.  Erase returns true if the file was
  300. deleted.
  301.  
  302.  
  303. function FileEntry.Rename(NewName:PathStr): Boolean; virtual;
  304. -------------------------------------------------------------
  305.  
  306.      Rename changes the name of the file on disk.  Returns true if the
  307. rename was successful.  Also calls ChangePath to change the name in
  308. memory.
  309.  
  310.  
  311. function FileEntry.ResetTime: Boolean;
  312. --------------------------------------
  313.  
  314.      ResetTime resets the filetime on disk to that stored in memory.
  315. This can be used for programs that update a file and need to reset the
  316. original time.  An example might be appending information to a text file
  317. and resetting the time so the file appears unmodified.
  318.  
  319.  
  320. function FileEntry.ResetAttr: Boolean;
  321. --------------------------------------
  322.  
  323.      ResetAttr is similar to FileEntry.ResetTime except it deals with
  324. the file attribute.
  325.  
  326.  
  327. function FileEntry.SetTime(T:Longint): Boolean; virtual;
  328. --------------------------------------------------------
  329.  
  330.      SetTime updates the time of the file on disk without changing the
  331. time in memory.  Descendant types could make a call to FileEntry.SetTime
  332. followed by a call to FileEntry.ChangeTime to update both, as this
  333. method is virtual.  SetTime returns true of the time was successfully
  334. changed.
  335.  
  336.  
  337. function FileEntry.SetAttr(A:AttrType): Boolean; virtual;
  338. ---------------------------------------------------------
  339.  
  340.      SetAttr is similar to FileEntry.SetTime except it deals with the
  341. file attribute.
  342.  
  343.  
  344. constructor FileEntry.Load(var S: Stream);
  345. ------------------------------------------
  346.  
  347.      Load calls BaseEntry.Load.  No data elements were introduced in
  348. FileEntry so no other data needs to be read from the stream.
  349.  
  350.  
  351. procedure FileEntry.Store(var S: Stream); virtual;
  352. --------------------------------------------------
  353.  
  354.      Store calls BaseEntry.Store.  No data elements were introduced in
  355. FileEntry so no other data needs to be stored on the stream.
  356.  
  357.  
  358. PDir.DirEntry
  359. -------------
  360.  
  361.      DirEntry is a descendant of PDir.FileEntry.  It introduces one new
  362. data element: DirEntries.  DirEntries is of type Objects.List.  It is to
  363. be used as a list of PDir.DirEntry for recursively searching
  364. subdirectories or searching just one directory.  This allows for easy
  365. file management and directory management.  The order of entries in the
  366. list can not be assumed to contain files then directories, or vice
  367. versa.  The entries are to be handled in an arbitrary manner.  However,
  368. the FindDirectories routine will append files to the list first, then
  369. directories.  This is useful for processing all files in a directory
  370. before proceeding to the subdirectories.  One technique would be to
  371. Insert any files and Append any directories to the list to maintain a
  372. consistent structure.  DirEntry nodes contain the DirEntries element,
  373. where FileEntry nodes do not.  To see the data structures used with
  374. DirEntry see DirEntry.FindFiles and DirEntry.FindDirectories.
  375.  
  376.  
  377. constructor DirEntry.Init;
  378. --------------------------
  379.  
  380.      Init will call FileEntry.Init and delete the entries in the
  381. DirEntries list.  This should not be used as a parameter to New() as
  382. DirEntries may contain uninitialized data immediately after allocation.
  383. This may be called after the object has been allocated to delete the
  384. items from DirEntries and reset the FileEntry information.
  385.  
  386.  
  387. constructor DirEntry.Clear;
  388. ---------------------------
  389.  
  390.      Clear first clears the DirEntries list and then calls
  391. DirEntry.Init.  This should be used as the parameter to a dynamic object
  392. allocation.
  393.  
  394.             var
  395.               DP: DirEntryPtr;
  396.             ...
  397.             New(DP,Clear);
  398.             ...
  399.  
  400.  
  401. destructor DirEntry.Done; virtual;
  402. ----------------------------------
  403.  
  404.      Done deletes the entries in DirEntries and then calls
  405. FileEntry.Done.
  406.  
  407.  
  408. procedure DirEntry.FindFiles(FileSpec: PathStr; Attrib: AttrType);
  409. ------------------------------------------------------------------
  410.  
  411.      FindFiles is a front end for the FindFirst and FindNext found in
  412. the System unit.  FileSpec can contain wildcards but must not contain a
  413. path; the current directory on the currently logged drive is processed.
  414. FindFiles creates a List of FileEntry nodes for all files in the current
  415. directory that match the parameters.  If Attrib includes the Directory
  416. attribute then subdirectory names will be included as normal files in
  417. the list.  Those directories will not be recursively scanned for files.
  418. This allows creation of a list that contains files and subdirectories
  419. (stored as normal file entries) without scanning all subdirectories. In
  420. general the Directory attribute would not be passed. The list is stored
  421. in DirEntry.FileList.
  422.  
  423.   Example for DirEntry.FindFiles:
  424.  
  425.         procedure GetSourceFileList;
  426.           var
  427.             SourceDir: DirEntryPtr;
  428.           begin
  429.           ChDir('C:\PROGRAM\SOURCE');
  430.           New(SourceDir,Clear);
  431.           SourceDir^.FindFiles('*.PAS',Dos.Archive);
  432.           end;
  433.  
  434.         SourceDir^.FileList might contain:
  435.  
  436.         ┌────────────┬─┐  ┌────────────┬─┐  ┌────────────┬─┐
  437.         │DYNABOOT.PAS│─┼─│DBOBJ.PAS   │─┼─│DBEDITOR.PAS│─┼─┐
  438.         └────────────┴─┘  └────────────┴─┘  └────────────┴─┘ │
  439.                                                            ──┴──
  440.                                                             ───
  441.                                                              ─
  442.  
  443.  
  444. procedure DirEntry.FindDirectories(FileSpec: PathStr; Attrib: AttrType);
  445. ------------------------------------------------------------------------
  446.  
  447.      FindDirectories is an extended version of FindFiles that
  448. recursively searches subdirectories.  FindDirectories calls FindFiles if
  449. FileSpec is not empty.  The current directory is the first directory
  450. processed and will be returned to when FindDirectories ends.  This
  451. routine can be used to create a tree of the drive if FileSpec is empty.
  452. The data structure created by FindDirectories is shown by the following
  453. diagram of a root directory containing several files and \DOS:
  454.  
  455. ┌────────────┬─┐  ┌────────────┬─┐  ┌─────────┬─┬─┐
  456. │AUTOEXEC.BAT│─┼─│CONFIG.SYS  │─┼─│DOS      │ │─┼─┐
  457. └────────────┴─┘  └────────────┴─┘  └─────────┴┼┴─┘ │                                                                       ──┴──
  458.                                                │  ──┴──
  459.             ┌──────────────────────────────────┘   ───
  460.             │                                       ─
  461.             │  ┌────────────┬─┐  ┌────────────┬─┐  ┌────────────┬─┐
  462.             └─│ASSIGN.COM  │─┼─│BACKUP.COM  │─┼─│CHKDSK.COM  │─┼─┐
  463.                └────────────┴─┘  └────────────┴─┘  └────────────┴─┘ │
  464.                                                                   ──┴──
  465.                                                                    ───
  466.                                                                     ─
  467.  
  468. A simple shell of a program to process the data structure created by
  469. FindDirectories might be:
  470.  
  471.           procedure ProcessDir(D: DirEntryPtr);
  472.             var
  473.               DirPtr : DirEntryPtr;
  474.             begin
  475.             DirPtr := DirEntryPtr(D^.DirEntries.First);
  476.             while DirPtr <> nil do
  477.               begin
  478.               if DirPtr^.IsDirectory then
  479.                 ProcessDir(DirPtr); {recursively process subdirectories}
  480.               else
  481.                 {process file};
  482.               DirPtr := DirEntryPtr(D^.DirEntries.Next(DirPtr));
  483.               end;
  484.             end;
  485.  
  486.  
  487. constructor DirEntries.Load(var S: Stream);
  488. -------------------------------------------
  489.  
  490.      Load calls FileEntry.Load and then calls DirEntries.Load.  This is
  491. also a constructor and can be a suitable replacement for Clear or Init.
  492.  
  493.  
  494. procedure DirEntries.Store(var S: Stream); virtual;
  495. ----------------------------------------
  496.  
  497.      Store calls FileEntry.Store and then calls DirEntries.Store.
  498.  
  499.  
  500. PDir.DirStream
  501. --------------
  502.  
  503.      DirStream is a descendant of Objects.DosStream used to store
  504. BaseEntry, FileEntry and DirEntry objects on disk.  The only method is
  505. RegisterTypes, but it should never be called by a program; RegisterTypes
  506. is called by the Stream routines.
  507.  
  508.      Example:
  509.  
  510.           program WriteStructure;
  511.             var
  512.               DP: DirEntryPtr;
  513.               DS: DirStream;
  514.             begin
  515.             ChDir('C:\');
  516.             New(DP,Clear);
  517.             DP^.FindDirectories('*.ZIP',AnyFile);
  518.             DS.Init('C:\ZIPFILES.DAT',SCreate);
  519.             DP^.Store(DS);
  520.             DS.Done;
  521.             Dispose(DP,Done);
  522.             end;
  523.  
  524.  
  525. function PDir.ReadString(var S: Stream): String;
  526. ------------------------------------------------
  527.  
  528.      ReadString returns a string from the current position in Stream S.
  529.  
  530.  
  531. procedure PDir.WriteString(var S: Stream; Str: String);
  532. -------------------------------------------------------
  533.  
  534.      WriteString will write the string Str to the Stream S.  Only the
  535. characters that belong to the string will be written.  Ordinarily, a
  536. definition like:
  537.  
  538.      TYPE
  539.        Str80: String[80]
  540.  
  541. results in any variable of type Str80 requiring 81 bytes of storage (80
  542. bytes plus one byte to store the length).   Writing a Str80 with
  543. SizeOf(Str80) would always write 81 bytes to the stream.  WriteString
  544. only writes (Length(Str) + 1) bytes to the stream, keeping the stream as
  545. garbage free as is possible.
  546.  
  547.  
  548. function PDir.ExtensionPos(FName : PathStr): Word;
  549. --------------------------------------------------
  550.  
  551.      ExtensionPos is used internally by PDir to find the position of the
  552. period in a PathStr.  This can be useful for any routines that may need
  553. to manipulate a file extension based on its position in the PathStr.
  554.  
  555.  
  556. function PDir.CurDir: PathStr;
  557. ------------------------------
  558.  
  559.     CurDir acts as a front end to the System.GetDir procedure. CurDir
  560. assumes that the current drive (drive 0 according to GetDir) is the
  561. drive requested.  Ordinarily a variable is needed as well as a call to
  562. GetDir, followed by the code that needs the current directory.  CurDir
  563. can be used to pass the current directory to a routine in one shot.
  564.  
  565.      Example:
  566.  
  567.           ...
  568.           WriteLn('Current directory: ',CurDir);
  569.           ...
  570.  
  571.  
  572. END.
  573.