home *** CD-ROM | disk | FTP | other *** search
- PDir v1.0, 18 Aug 89
-
- Palcic Directory Routines
- -------------------------
-
- Matthew J. Palcic
- MJP Enterprises
- 1030 Dayton-Yellow Springs Rd.
- Xenia, OH 45385-9508
-
- The routines in PDir are Copyright (C) 1989 by Matthew J. Palcic.
- The code is public domain, but a donation would be greatly appreciated.
- Any suggestions for modifications/additions to the source code are
- welcome. However, the source code is to be distributed only in its
- original, unmodified form. MJP Enterprises reserves the rights to all
- code and documentation included with PDir. MJP Enterprises and Matthew
- J. Palcic shall not be held responsible for any damages resulting from
- the use of this code. No warranty is offered (express or written) for
- the performance or accuracy of the documentation and source code. If
- you plan to use PDir for a distribution program (shareware, public
- domain or commercial) please inform Matthew Palcic at the address above.
- I'd like to know who's using my code and for what purposes.
-
- PDir was developed using Turbo Pascal 5.5 on a 286 machine running
- MS-DOS 4.01. Requires the Objects unit found on the Turbo Pascal 5.5
- distribution disks.
-
- The routines in the PDir unit are based almost entirely on the
- object-oriented extensions in Turbo Pascal 5.5. The user should be
- familiar with the stream, node and list types found in the Objects unit
- provided in OOPDEMOS.ARC found on the Turbo 5.5 distribution disks. Also
- an understanding of recursive calls is helpful but not required to use
- the routines. Even though there are many methods which may not be used
- in a program, the smart linker will eliminate all unused methods at
- compile time. The data elements in the objects should not be directly
- accessed in a program; the methods defined for each object should be
- sufficient forms of access to the data elements. If these routines do
- not fill a need, define a descendant object type that inherits all the
- other routines and adds the function you need. It is strongly
- recommended that the user employ these objects as dynamic (using their
- Ptr counterparts) rather than static. This offers much more flexibility
- than the static routines can offer.
-
- Throughout this documentation a compact notation is used to
- describe any elements or routines from other units. Turbo Pascal allows
- a unit specifier to precede any items in the unit to prevent ambiguity
- (such two procedures having the same name.)
-
- An example:
-
- PDir defines a routine Rename that calls the Dos unit's routine
- Rename. Calling Rename does not clearly call either version so
- PDir.Rename and Dos.Rename explicitly call one or the other.
-
- This notation is also used to specify where a routine, variable, etc.
- originates. Rather than saying 'The NameStr type found in the Dos unit'
- the documentation would read Dos.NameStr. Sufficient documentation is
- found in the Turbo Pascal manual such that they need not be explained
- here. The examples will build on other methods in the object for
- clarity.
-
-
- FileStr
- -------
-
- FileStr is used to combine a filename into one string rather than
- the separate Dos.NameStr and Dos.ExtStr. FileStr includes the '.'
- before the extension.
-
-
- PDir.BaseEntry
- --------------
-
- BaseEntry is the ancestor to FileEntry and DirEntry described
- later. This contains all of the information found in a Dos.SearchRec
- except for SearchRec.Fill. Fill is not used by any of the routines in
- PDir or any other program I've seen for that matter. The data elements
- contained in BaseEntry include the Name, Attribute, Size and Time
- (stored in standard packed format; see PackTime/UnpackTime). The
- function methods return the values stored in memory and may not reflect
- current data if the disk was updated after creating the object.
-
-
- constructor BaseEntry.Init;
- ---------------------------
-
- Dummy constructor routine meant to be overridden by descendant
- types.
-
-
- destructor BaseEntry.Done; virtual;
- -----------------------------------
-
- Dummy destructor routine meant to be overridden by descendant
- types.
-
-
- procedure BaseEntry.ConvertRec(S: SearchRec);
- ---------------------------------------------
-
- ConvertRec converts Dos.SearchRec 'S' into the data elements needed
- in BaseEntry. SearchRec.Fill is ignored.
-
- uses Dos;
- procedure GetFirstFile;
- var
- DirInfo: Dos.SearchRec;
- FirstFile: BaseEntry;
- begin
- ChDir('C:\');
- FirstFile.Init; { Must call the constructor }
- FindFirst('*.*',Dos.Archive,DirInfo);
- FirstFile.ConvertRec(DirInfo);
- ...
-
- function BaseEntry.FileName: NameStr; virtual;
- ----------------------------------------------
-
- FileName returns the entire filename including the extension, which
- is often more useful than using FileName+FileExt. This is a virtual
- routine, so a descendant type may define FileName to return only the
- filename without the extension.
-
- WriteLn('Filename: ',FirstFile.FileName);
-
- Result:
- Filename: AUTOEXEC.BAT
-
-
- function BaseEntry.FileExt: ExtStr;
- -----------------------------------
-
- FileExt returns only the extension of the file, without the period.
- This method is virtual, so descendant types may define FileExt to
- include the period.
-
- WriteLn('Extension only: ',FirstFile.FileExt);
-
- Result:
- Extension only: BAT
-
-
- function BaseEntry.FullName: PathStr; virtual;
- ----------------------------------------------
-
- FullName returns the same string as BaseEntry.FileName. It is
- virtual so that descendant types may include a FilePath data element and
- define FullName to return the FilePath and FileName in one string.
-
-
- function BaseEntry.FileTime: Longint; virtual;
- ----------------------------------------------
-
- FileTime returns the file time in standard packed format (Longint).
- See Dos.PackTime and Dos.UnpackTime and the Dos.DateTime record. It is
- virtual to allow descendant types to return current data from the disk
- on every call, rather than returning values stored in the object. This
- would allow other routines to update a file and let FileTime return the
- new filetime.
-
- var
- DT: DateTime;
- begin
- UnpackTime(FirstFile.FileTime,DT);
- WriteLn(FirstFile.FullName);
- WriteLn(Month:2,'/',Day:2,'/',(Year - 1900):2);
- WriteLn(Hour:2,':',Min:2,':',Sec:2);
- end;
-
- Result:
- AUTOEXEC.BAT
- 11/13/88
- 12:35:26
-
-
- function BaseEntry.FileAttr: AttrType; virtual;
- -----------------------------------------------
-
- FileAttr returns the attribute of the file. Constants describing
- the bit fields of the returned AttrType are described under 'Files,
- Attributes, Constants'. This is virtual to allow real-time checking of
- the file attribute (especially useful for file sharing).
-
-
- function BaseEntry.FileSize: Longint; virtual;
- ----------------------------------------------
-
- FileSize returns the total size (in bytes) of the file. This is
- virtual to allow the FileSize to return the current size, rather than
- the size in memory.
-
- function BaseEntry.IsDirectory: Boolean;
- ----------------------------------------
-
- Returns True if the file attribute contains the Directory bit.
-
-
- constructor BaseEntry.Load(var S: Stream);
- ------------------------------------------
-
- Load will read in an object of type BaseEntry from a stream. This
- is a constructor and is a suitable replacement for using BaseEntry.Init.
-
- var
- Strm: PDir.DirStream;
- begin
- Strm.Init('C:\FILE.DAT',SOpen);
- FirstFile.Load(Strm);
- Strm.Done;
- end;
-
-
- procedure BaseEntry.Store(var S: Stream); virtual;
- --------------------------------------------------
-
- Store will write the data in a BaseEntry instance to a stream.
-
- var
- Strm: PDir.DirStream;
- begin
- Strm.Init('C:\FILE.DAT',SCreate);
- FirstFile.Store(Strm);
- Strm.Done;
- end;
-
-
- PDir.FileEntry
- --------------
-
- A descendant of BaseEntry offering methods to change any of the
- elements in BaseEntry. No new data elements are defined.
-
-
- constructor FileEntry.Init;
- ---------------------------
-
- Initializes the data elements to acceptable empty values to prevent
- impossible dates, times, filenames, etc.
-
-
- destructor FileEntry.Done; virtual;
- -----------------------------------
-
- Dummy destructor that calls BaseEntry.Done;
-
-
- procedure FileEntry.ForceExt(E:ExtStr);
- ---------------------------------------
-
- ForceExt accepts a file extension (without the period) and forces
- it on the filename. This is useful for changing a .DAT file to a .BAK
- file, etc. This calls Rename to change the name of the file on disk and
- in memory.
-
- ...
- WriteLn('Old name: ',FileEntry.FullName);
- FileEntry.ForceExt('ZIP');
- WriteLn('New name: ',FileEntry.FullName);
- ...
-
- Old name: GARBAGE.ARC
- New name: GARBAGE.ZIP
-
-
- procedure FileEntry.ChangeName(P:PathStr); virtual;
- ---------------------------------------------------
-
- ChangeName will only change the filename in memory. Rename should
- be used to change the name on disk.
-
-
- procedure FileEntry.ChangePath(P:PathStr); virtual;
- ---------------------------------------------------
-
- ChangePath performs the same function as ChangeName. Descendant
- types should declare ChangePath to change the path and the filename.
-
-
- procedure FileEntry.ChangeTime(T:Longint); virtual;
- ---------------------------------------------------
-
- ChangeTime only changes the time in memory. SetTime should be used
- to update the time on disk.
-
-
- procedure FileEntry.ChangeAttr(A:AttrType); virtual;
- ----------------------------------------------------
-
- ChangeAttr only changes the attribute in memory. SetAttr should be
- used to change the attribute on disk.
-
-
- function FileEntry.Erase: Boolean; virtual;
- -----------------------------------
-
- Erase will remove the file from the directory. If the file is
- locked or has read-only status the file will not be deleted. Descendant
- types could define Erase to set the attribute to allow deletion
- regardless of the current attribute. Erase returns true if the file was
- deleted.
-
-
- function FileEntry.Rename(NewName:PathStr): Boolean; virtual;
- -------------------------------------------------------------
-
- Rename changes the name of the file on disk. Returns true if the
- rename was successful. Also calls ChangePath to change the name in
- memory.
-
-
- function FileEntry.ResetTime: Boolean;
- --------------------------------------
-
- ResetTime resets the filetime on disk to that stored in memory.
- This can be used for programs that update a file and need to reset the
- original time. An example might be appending information to a text file
- and resetting the time so the file appears unmodified.
-
-
- function FileEntry.ResetAttr: Boolean;
- --------------------------------------
-
- ResetAttr is similar to FileEntry.ResetTime except it deals with
- the file attribute.
-
-
- function FileEntry.SetTime(T:Longint): Boolean; virtual;
- --------------------------------------------------------
-
- SetTime updates the time of the file on disk without changing the
- time in memory. Descendant types could make a call to FileEntry.SetTime
- followed by a call to FileEntry.ChangeTime to update both, as this
- method is virtual. SetTime returns true of the time was successfully
- changed.
-
-
- function FileEntry.SetAttr(A:AttrType): Boolean; virtual;
- ---------------------------------------------------------
-
- SetAttr is similar to FileEntry.SetTime except it deals with the
- file attribute.
-
-
- constructor FileEntry.Load(var S: Stream);
- ------------------------------------------
-
- Load calls BaseEntry.Load. No data elements were introduced in
- FileEntry so no other data needs to be read from the stream.
-
-
- procedure FileEntry.Store(var S: Stream); virtual;
- --------------------------------------------------
-
- Store calls BaseEntry.Store. No data elements were introduced in
- FileEntry so no other data needs to be stored on the stream.
-
-
- PDir.DirEntry
- -------------
-
- DirEntry is a descendant of PDir.FileEntry. It introduces one new
- data element: DirEntries. DirEntries is of type Objects.List. It is to
- be used as a list of PDir.DirEntry for recursively searching
- subdirectories or searching just one directory. This allows for easy
- file management and directory management. The order of entries in the
- list can not be assumed to contain files then directories, or vice
- versa. The entries are to be handled in an arbitrary manner. However,
- the FindDirectories routine will append files to the list first, then
- directories. This is useful for processing all files in a directory
- before proceeding to the subdirectories. One technique would be to
- Insert any files and Append any directories to the list to maintain a
- consistent structure. DirEntry nodes contain the DirEntries element,
- where FileEntry nodes do not. To see the data structures used with
- DirEntry see DirEntry.FindFiles and DirEntry.FindDirectories.
-
-
- constructor DirEntry.Init;
- --------------------------
-
- Init will call FileEntry.Init and delete the entries in the
- DirEntries list. This should not be used as a parameter to New() as
- DirEntries may contain uninitialized data immediately after allocation.
- This may be called after the object has been allocated to delete the
- items from DirEntries and reset the FileEntry information.
-
-
- constructor DirEntry.Clear;
- ---------------------------
-
- Clear first clears the DirEntries list and then calls
- DirEntry.Init. This should be used as the parameter to a dynamic object
- allocation.
-
- var
- DP: DirEntryPtr;
- ...
- New(DP,Clear);
- ...
-
-
- destructor DirEntry.Done; virtual;
- ----------------------------------
-
- Done deletes the entries in DirEntries and then calls
- FileEntry.Done.
-
-
- procedure DirEntry.FindFiles(FileSpec: PathStr; Attrib: AttrType);
- ------------------------------------------------------------------
-
- FindFiles is a front end for the FindFirst and FindNext found in
- the System unit. FileSpec can contain wildcards but must not contain a
- path; the current directory on the currently logged drive is processed.
- FindFiles creates a List of FileEntry nodes for all files in the current
- directory that match the parameters. If Attrib includes the Directory
- attribute then subdirectory names will be included as normal files in
- the list. Those directories will not be recursively scanned for files.
- This allows creation of a list that contains files and subdirectories
- (stored as normal file entries) without scanning all subdirectories. In
- general the Directory attribute would not be passed. The list is stored
- in DirEntry.FileList.
-
- Example for DirEntry.FindFiles:
-
- procedure GetSourceFileList;
- var
- SourceDir: DirEntryPtr;
- begin
- ChDir('C:\PROGRAM\SOURCE');
- New(SourceDir,Clear);
- SourceDir^.FindFiles('*.PAS',Dos.Archive);
- end;
-
- SourceDir^.FileList might contain:
-
- ┌────────────┬─┐ ┌────────────┬─┐ ┌────────────┬─┐
- │DYNABOOT.PAS│─┼─│DBOBJ.PAS │─┼─│DBEDITOR.PAS│─┼─┐
- └────────────┴─┘ └────────────┴─┘ └────────────┴─┘ │
- ──┴──
- ───
- ─
-
-
- procedure DirEntry.FindDirectories(FileSpec: PathStr; Attrib: AttrType);
- ------------------------------------------------------------------------
-
- FindDirectories is an extended version of FindFiles that
- recursively searches subdirectories. FindDirectories calls FindFiles if
- FileSpec is not empty. The current directory is the first directory
- processed and will be returned to when FindDirectories ends. This
- routine can be used to create a tree of the drive if FileSpec is empty.
- The data structure created by FindDirectories is shown by the following
- diagram of a root directory containing several files and \DOS:
-
- ┌────────────┬─┐ ┌────────────┬─┐ ┌─────────┬─┬─┐
- │AUTOEXEC.BAT│─┼─│CONFIG.SYS │─┼─│DOS │ │─┼─┐
- └────────────┴─┘ └────────────┴─┘ └─────────┴┼┴─┘ │ ──┴──
- │ ──┴──
- ┌──────────────────────────────────┘ ───
- │ ─
- │ ┌────────────┬─┐ ┌────────────┬─┐ ┌────────────┬─┐
- └─│ASSIGN.COM │─┼─│BACKUP.COM │─┼─│CHKDSK.COM │─┼─┐
- └────────────┴─┘ └────────────┴─┘ └────────────┴─┘ │
- ──┴──
- ───
- ─
-
- A simple shell of a program to process the data structure created by
- FindDirectories might be:
-
- procedure ProcessDir(D: DirEntryPtr);
- var
- DirPtr : DirEntryPtr;
- begin
- DirPtr := DirEntryPtr(D^.DirEntries.First);
- while DirPtr <> nil do
- begin
- if DirPtr^.IsDirectory then
- ProcessDir(DirPtr); {recursively process subdirectories}
- else
- {process file};
- DirPtr := DirEntryPtr(D^.DirEntries.Next(DirPtr));
- end;
- end;
-
-
- constructor DirEntries.Load(var S: Stream);
- -------------------------------------------
-
- Load calls FileEntry.Load and then calls DirEntries.Load. This is
- also a constructor and can be a suitable replacement for Clear or Init.
-
-
- procedure DirEntries.Store(var S: Stream); virtual;
- ----------------------------------------
-
- Store calls FileEntry.Store and then calls DirEntries.Store.
-
-
- PDir.DirStream
- --------------
-
- DirStream is a descendant of Objects.DosStream used to store
- BaseEntry, FileEntry and DirEntry objects on disk. The only method is
- RegisterTypes, but it should never be called by a program; RegisterTypes
- is called by the Stream routines.
-
- Example:
-
- program WriteStructure;
- var
- DP: DirEntryPtr;
- DS: DirStream;
- begin
- ChDir('C:\');
- New(DP,Clear);
- DP^.FindDirectories('*.ZIP',AnyFile);
- DS.Init('C:\ZIPFILES.DAT',SCreate);
- DP^.Store(DS);
- DS.Done;
- Dispose(DP,Done);
- end;
-
-
- function PDir.ReadString(var S: Stream): String;
- ------------------------------------------------
-
- ReadString returns a string from the current position in Stream S.
-
-
- procedure PDir.WriteString(var S: Stream; Str: String);
- -------------------------------------------------------
-
- WriteString will write the string Str to the Stream S. Only the
- characters that belong to the string will be written. Ordinarily, a
- definition like:
-
- TYPE
- Str80: String[80]
-
- results in any variable of type Str80 requiring 81 bytes of storage (80
- bytes plus one byte to store the length). Writing a Str80 with
- SizeOf(Str80) would always write 81 bytes to the stream. WriteString
- only writes (Length(Str) + 1) bytes to the stream, keeping the stream as
- garbage free as is possible.
-
-
- function PDir.ExtensionPos(FName : PathStr): Word;
- --------------------------------------------------
-
- ExtensionPos is used internally by PDir to find the position of the
- period in a PathStr. This can be useful for any routines that may need
- to manipulate a file extension based on its position in the PathStr.
-
-
- function PDir.CurDir: PathStr;
- ------------------------------
-
- CurDir acts as a front end to the System.GetDir procedure. CurDir
- assumes that the current drive (drive 0 according to GetDir) is the
- drive requested. Ordinarily a variable is needed as well as a call to
- GetDir, followed by the code that needs the current directory. CurDir
- can be used to pass the current directory to a routine in one shot.
-
- Example:
-
- ...
- WriteLn('Current directory: ',CurDir);
- ...
-
-
- END.
-