DFUtilities.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin on November 3, 1983 12:26 am
Russ Atkinson (RRA) February 13, 1985 11:35:28 am PST
DIRECTORY
BasicTime USING [GMT, nullGMT],
IO USING [STREAM],
Rope USING [ROPE];
DFUtilities: CEDAR DEFINITIONS = BEGIN OPEN BasicTime, IO, Rope;
The following types define the "items" that can appear in a DF.
DirectoryItem: TYPE = RECORD [
path1: ROPE,
path2: ROPE,
path2IsCameFrom: BOOL, -- only meaningful if path2 is non-NIL; FALSE means "ReleaseAs"
exported: BOOL, -- if TRUE, "Exports" preceded or replaced "Directory"
readOnly: BOOL -- if TRUE, "ReadOnly" preceded or replaced "Directory"
];
FileItem: TYPE = RECORD [
name: ROPE, -- a short name
date: Date,
verifyRoot: BOOL -- if TRUE, file item was preceded by a "+"
];
ImportsItem: TYPE = RECORD [
path1: ROPE,
date: Date,
path2: ROPE, -- if non-NIL, path following "CameFrom"
exported: BOOL, -- if TRUE, "Exports" preceded or followed "Imports"
form: UsingForm,
list: REF UsingList -- NIL iff form ~= list
];
IncludeItem: TYPE = RECORD [
path1: ROPE,
date: Date,
path2: ROPE,
path2IsCameFrom: BOOL -- only meaningful if path2 is non-NIL; FALSE means "ReleaseAs"
];
CommentItem: TYPE = RECORD [
text: ROPE -- exact text, including comment characters
];
WhiteSpaceItem: TYPE = RECORD [
lines: NAT
];
These types "complete" the above declarations.
DateFormat: TYPE = {explicit, omitted, greaterThan, notEqual};
Date: TYPE = RECORD [
format: DateFormat ← $omitted,
gmt: GMT ← nullGMT
'gmt' is valid only if dateFormat = $explicit. (We don't use a variant record because it complicates the client's life too much (i.e., the compiler is unnecessarily picky about assignments involving variant records that aren't REF-containing).)
];
Note: Dates returned by ParseFromStream are guaranteed to have `gmt' = nullGMT if `format' ~= $explicit. The other procedures of this interface ignore the 'gmt' field if 'format' ~= $explicit.
UsingForm: TYPE = {exports, all, list};
UsingList: TYPE = RECORD [nEntries: NAT, u: SEQUENCE length: NAT OF UsingEntry];
UsingEntry: TYPE = RECORD [
verifyRoot: BOOLFALSE, -- if TRUE, file name was preceded by a "+"
name: ROPE -- a short name
];
Procedures
ParseFromStream: PROC [in: STREAM, proc: ProcessItemProc, filter: Filter ← []];
This procedure reads a DF from the stream 'in'. The DF is assumed to begin at the current stream position and terminate when EndOfStream is raised. For each item parsed, 'filter' is examined and, if the item "passes" the filter, as described below, 'proc' is invoked with the item as a parameter.
ProcessItemProc: TYPE = PROC [item: REF ANY] RETURNS [stop: BOOLFALSE];
The type of the parameter will be one of: DirectoryItem, FileItem, ImportsItem, IncludeItem, CommentItem, or WhiteSpaceItem. If the ProcessItemProc returns TRUE, parsing terminates; that is, ParseFromStream returns to its caller. In this case, the precise position of the stream relative to the last item processed cannot be guaranteed. If the ProcessItemProc returns FALSE (the normal case), ParseFromStream continues until end-of-stream or a syntax error occurs.
SyntaxError: ERROR [reason: ROPE];
This error is raised by ParseFromStream when a syntax error is detected in the input DF. The input stream is positioned close to the point of the error, but the precise position cannot be guaranteed. 'reason' is a brief prose description of the error and is intended for human, not program, interpretation.
Filter: TYPE = RECORD [
comments: BOOLFALSE,
filterA: FilterA ← $all,
filterB: FilterB ← $all,
filterC: FilterC ← $all,
list: REF UsingList ← NIL
];
Items are said to "pass" a Filter under the following conditions:
* A Comment item passes the filter iff 'comments' is TRUE.
* A WhiteSpace item passes the filter iff 'comments' is TRUE and the item immediately following it (which cannot be another WhiteSpace item) passes the filter. This implies that the last item passed is never WhiteSpace; i.e., terminal white space in the input stream will not be reported to the ProcessItemProc.
* A DirectoryItem passes the filter iff its 'exported' and 'readOnly' attributes are consistent with 'filterB' and 'filterC', respectively. If a DirectoryItem is skipped, all FileItems under it will be skipped as well. However, a DirectoryItem may be passed without any of the FileItems under it being passed.
* A FileItem passes the filter iff (1) the preceding DirectoryItem was passed, (2) the file name passes 'filterA' and, (3) if 'list' is non-NIL, the file name appears in the list.
* An IncludeItem always passes the filter.
* An ImportsItem passes the filter only if its 'exported' attribute is consistent with 'filterB' and 'filterC' is '$imported' or '$all'. The 'form' and 'list' fields of the ImportsItem are determined by "intersecting" in the obvious way the contents of the input DF and the Filter's 'filterA' and 'list' fields. If this intersection is empty, the ImportsItem is not passed.
FilterA: TYPE = {source, derived, all};
This subfilter screens files according to the origin of their bits. 'derived' means files whose extensions identify files produced mechanically from other files. This includes files with extension "bcd", "boot", "press", and "signals". 'source' really means "not derived"; that is, files with no extension or with an extension that aren't recognized as 'derived'. 'all' passes all files.
FilterB: TYPE = {public, private, all};
This subfilter screens files by their interest to a client. 'public' files are those that a client would want to see (i.e., those that the DF file Exports). 'private' files are all others. 'all' passes all files.
FilterC: TYPE = {defining, imported, all};
This subfilter screens files by the nature of the entry in which they appear. An 'imported' instance is a file that appears in an Imports statement (including the DF file being imported). A 'defining' instance is any other appearance of a file; that is, one that can potentially include a date. 'all' passes all files.
WriteToStream: PROC [out: STREAM, proc: SupplyItemProc];
This procedure writes a DF to the stream 'out'. 'proc' is called to supply each item to be written; if NIL is returned, WriteToStream terminates. The stream is not closed upon completion of writing. If the items are supplied in an incorrect order, or if some call of 'proc' returns an item of unknown type, 'SyntaxError' is raised.
SupplyItemProc: TYPE = PROC RETURNS [REF ANY];
The type of the (referent of the) return value must be one of: DirectoryItem, FileItem, ImportsItem, IncludeItem, CommentItem, or WhiteSpaceItem.
WriteItemToStream: PROC [out: STREAM, item: REF ANY];
This procedure writes a single item to the stream 'out'. The type of (the referent of) 'item' must be one of: DirectoryItem, FileItem, ImportsItem, IncludeItem, CommentItem, or WhiteSpaceItem. Otherwise, 'SyntaxError' is raised.
SortUsingList: PROC [usingList: REF UsingList, nearlySorted: BOOLFALSE];
This procedure sorts a using list, replacing the old one with the sorted one. No attempt is made to remove duplicates. The 'nearlySorted' parameter controls the speed of the algorithm used. It should be set to TRUE if the input UsingList is mostly sorted, since the algorithm then minimizes shuffling of the entries and the reference counting it implies.
SearchUsingList: PROC [file: ROPE, list: REF UsingList] RETURNS [found: BOOL, index: NAT];
This procedure searches for 'file' in 'list'. If 'list' is NIL, it returns found: TRUE, and `index' undefined; otherwise, it returns TRUE iff file is present in 'list', and `index' is the position in list.u where 'file' appears. It is assumed that 'list' has been sorted by SortUsingList.
DifferenceOfUsingLists: PROC [a, b: REF UsingList] RETURNS [diff: REF UsingList];
This procedure returns a using list containing all the member of 'a' that do not appear in 'b'. It assumes that both 'a' and 'b' have been sorted by SortUsingList.
DateToRope: PROC [date: Date] RETURNS [ROPE];
This procedure converts the input date to a standard text representation for use in a DF file. To ensure uniformity, it should be used in preference to conversions through the IO interface.
DateToStream: PROC [s: STREAM, date: Date];
This procedure is identical to DateToRope, but produces its output on the stream 's'.
ClassifyFileExtension: PROC [file: ROPE] RETURNS [FilterA];
This procedure checks the file extension and classifies the file as either 'source' or 'derived'. FilterA.all is never returned.
GetVersionNumber: PROC [r: ROPE] RETURNS [ROPE];
This procedure returns the version number, including "!", if present. If no version number is present, an empty ROPE is returned.
RemoveVersionNumber: PROC [r: ROPE] RETURNS [ROPE];
This procedure removes any trailing file version number; i.e., from the first occurrence of "!", if any, to the end of the rope.
END.