DFUtilitiesExtrasImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Created by Bertrand Serlet, August 28, 1986 4:31:08 pm PDT
Bertrand Serlet September 27, 1986 5:19:01 pm PDT
DIRECTORY DFUtilities, DFUtilitiesExtras, FS, IO, Rope, RopeHash;
DFUtilitiesExtras
Impl:
CEDAR
PROGRAM
IMPORTS DFUtilities, FS, IO, Rope, RopeHash
EXPORTS DFUtilitiesExtras
~ BEGIN OPEN DFUtilities, DFUtilitiesExtras, Rope;
CacheArray: TYPE = ARRAY [0 .. cacheSize) OF ParsedDF;
cacheSize: CARDINAL = 01019;
cache:
REF CacheArray ←
NEW [CacheArray ←
ALL [
NIL]];
ParsedDF: TYPE = REF ParsedDFRep;
ParsedDFRep:
TYPE =
RECORD [
dfFullName: ROPE,
items: SEQUENCE size: NAT OF REF ANY
];
FileSyntaxError:
PUBLIC ERROR [reason:
ROPE, position:
INT] =
CODE;
ParseDFFile:
PROC [df:
ROPE]
RETURNS [parsedDF: ParsedDF] = {
cp: FS.ComponentPositions;
dfFullName: ROPE;
hash: CARDINAL;
[fullFName: dfFullName, cp: cp] ← FS.ExpandName[df];
IF cp.server.length=0 OR cp.ver.length=0 OR NOT Rope.Equal[df, dfFullName] OR Rope.Fetch[df, Rope.Length[df]-1]='h OR Rope.Fetch[df, Rope.Length[df]-1]='l OR Rope.Fetch[df, Rope.Length[df]-1]='H OR Rope.Fetch[df, Rope.Length[df]-1]='L THEN dfFullName ← FS.FileInfo[df].fullFName; -- we try to avoid an expensive FS.FileInfo
hash ← RopeHash.FromRope[dfFullName, FALSE] MOD cacheSize;
parsedDF ← cache[hash];
IF parsedDF#NIL AND Rope.Equal[parsedDF.dfFullName, dfFullName, FALSE] THEN RETURN;
Let us start the real work!
BEGIN
dfStream: IO.STREAM ← FS.StreamOpen[fileName: dfFullName];
count: NAT ← 0;
items: LIST OF REF ANY ← NIL;
ProcessItem: ProcessItemProc = {items ← CONS [item, items]; count ← count + 1};
ParseFromStream[dfStream, ProcessItem, [comments:
TRUE]
! SyntaxError => {
position: INT = IO.GetIndex[dfStream];
IO.Close[dfStream];
ERROR FileSyntaxError[reason, position];
}];
IO.Close[dfStream];
parsedDF ← NEW [ParsedDFRep[count]];
parsedDF.dfFullName ← dfFullName;
FOR i:
NAT
DECREASING
IN [0 .. count)
DO
parsedDF[i] ← items.first; items ← items.rest;
ENDLOOP;
cache[hash] ← parsedDF;
END;
};
ParseFromFile:
PUBLIC
PROC [df:
ROPE, proc: ProcessItemProc, filter: Filter ← []] = {
previousWhiteSpace: REF ANY ← NIL;
previousDirectoryPassed: BOOL ← FALSE;
parsedDF: ParsedDF ← ParseDFFile[df];
SortUsingList[filter.list];
FOR i:
NAT
IN [0 .. parsedDF.size)
DO
item: REF ANY ← parsedDF[i];
WITH item
SELECT
FROM
directory:
REF DirectoryItem => {
directoryFilterB: DFUtilities.FilterB = IF directory.exported THEN $public ELSE $private;
directoryFilterC: DFUtilities.FilterC = IF directory.readOnly THEN $imported ELSE $defining;
previousDirectoryPassed ← (filter.filterB = $all OR filter.filterB = directoryFilterB) AND (filter.filterC = $all OR filter.filterC = directoryFilterC);
IF NOT previousDirectoryPassed THEN LOOP;
};
file:
REF FileItem => {
PassesNameFilter:
PROC [file:
ROPE]
RETURNS [
BOOL] = {
SELECT
TRUE
FROM
filter.list # NIL => {};
filter.filterA = $all => {};
ClassifyFileExtension[file] = filter.filterA => {};
ENDCASE => RETURN[FALSE];
RETURN[SearchUsingList[file, filter.list].found]
};
IF NOT previousDirectoryPassed OR NOT PassesNameFilter[RemoveVersionNumber[file.name]] THEN LOOP;
};
import:
REF ImportsItem => {
list: REF UsingList ← import.list;
ConsiderImports:
PROC
RETURNS [
BOOL] = {
IF filter.filterC = $defining THEN RETURN [FALSE];
IF import.exported
AND filter.list #
NIL
THEN {
RRA sez: we should consider the imports of any imports item being exported when there is an explicit filter list. Of course, if there is a null intersection (list = NIL), we don't have to consider it unless the form dictates it.
RETURN [import.form = $all OR import.form = $exports OR list # NIL];
};
SELECT filter.filterB
FROM
$private => IF import.exported OR import.form = $exports THEN RETURN [FALSE];
$public => IF ~import.exported THEN RETURN [FALSE];
ENDCASE;
RETURN[~(import.form = $list AND list = NIL)]
};
IF filter.list=
NIL OR import.list
=NIL
THEN IF ConsiderImports[] THEN {} ELSE LOOP
ELSE {
last: NAT ← 0;
list ← NEW [UsingList[import.list.nEntries]];
FOR i:
NAT
IN [0 .. import.list.nEntries)
DO
IF NOT SearchUsingList[import.list[i].name, filter.list].found THEN LOOP;
list[last] ← import.list[i];
last ← last + 1;
ENDLOOP;
list.nEntries ← last;
SortUsingList[list];
IF ConsiderImports[]
THEN item ← NEW [ImportsItem ← [path1: import.path1, date: import.date, path2: import.path2, exported: import.exported, form: import.form, list: list]]
ELSE LOOP;
};
};
include: REF IncludeItem => {};
comment: REF CommentItem => IF NOT filter.comments THEN LOOP;
whiteSpace: REF WhiteSpaceItem => {IF filter.comments THEN previousWhiteSpace ← item; LOOP};
ENDCASE => ERROR;
IF previousWhiteSpace#
NIL
THEN {IF proc[previousWhiteSpace] THEN RETURN; previousWhiteSpace ← NIL};
IF proc[item] THEN RETURN;
ENDLOOP;
};
END.