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;
DFUtilitiesExtrasImpl: 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.STREAMFS.StreamOpen[fileName: dfFullName];
count: NAT ← 0;
items: LIST OF REF ANYNIL;
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 ANYNIL;
previousDirectoryPassed: BOOLFALSE;
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.