MorePfsEnumerationImpl.mesa
Copyright Ó 1990 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer on April 10, 1992 9:52 am PDT
DIRECTORY IO, MorePfsEnumeration, MorePfsNames, PFS, PFSNames, Process, Rope, RopeParts, SimpleFeedback;
MorePfsEnumerationImpl:
CEDAR
PROGRAM
IMPORTS IO, MorePfsNames, PFS, PFSNames, Process, RopeParts, SimpleFeedback
EXPORTS MorePfsEnumeration
=
BEGIN OPEN PFS, MorePfsEnumeration, RP:RopeParts, MPfsN:MorePfsNames, SF:SimpleFeedback;
RopePart: TYPE ~ RP.RopePart;
Component: TYPE ~ PFSNames.Component;
Version: TYPE ~ PFSNames.Version;
PatternSet: TYPE ~ LIST OF PATH;
debug: BOOL ← TRUE;
EnumerateForNames:
PUBLIC Enumerator ~ {
TransformEnumerator[PFS.EnumerateForNames, PfsCaser, PfsETester, pattern, proc, lbound, hbound];
RETURN};
EnumerateForInfo:
PUBLIC
PROC [pattern:
PATH, proc: InfoProc, lbound:
PATH ←
NIL, hbound:
PATH ←
NIL ] ~ {
PerName:
PROC [name:
PATH]
RETURNS [continue:
BOOL ←
TRUE] ~ {
RETURN APPLY[proc, PFS.FileInfo[name]]};
EnumerateForNames[pattern, PerName, lbound, hbound];
RETURN};
PfsCaser:
PUBLIC
PROC [name:
PATH]
RETURNS [sensitive:
BOOL] ~ {
sensitive ← FALSE;
sensitive ← PFS.CaseSensitive[name !PFS.Error => CONTINUE];
RETURN};
PfsETester:
PUBLIC
PROC [name:
PATH]
RETURNS [exists:
BOOL ←
FALSE] ~ {
ENABLE PFS.Error => CONTINUE;
exists ← PFS.FileInfo[name].bytes >= 0;
RETURN};
TransformEnumerator:
PUBLIC
PROC [base: Enumerator, caser: Caser, exists: ETester, pattern:
PATH, proc: NameProc, lbound:
PATH ←
NIL, hbound:
PATH ←
NIL ] ~ {
stopped: BOOL ← FALSE;
WorkFrom:
PROC [i:
INT, ps: PatternSet] ~ {
Enumerate each name that matches at least one pattern in ps.
The patterns each have at least i+1 components, and are identical up to (but not including) component i.
r: RopePart;
v: Version;
dvg, hastar: BOOL;
stem, lag: PATH ← NIL;
laghps, lagnhps: PatternSet ← NIL;
dhlag, dnhlag: BOOL ← FALSE;
Continue: NameProc ~ {
case, deliver, dlow, dhigh, newSeries: BOOL ← FALSE;
nps, elowps, ehighps: PatternSet ← NIL;
IF stopped THEN RETURN [FALSE];
Process.CheckForAbort[];
[case, deliver, nps, dlow, dhigh, elowps, ehighps] ← RefinePatterns[i, name, ps, caser];
IF dlow
OR dhlag
OR elowps#
NIL
OR laghps#
NIL
THEN {
newSeries ← lag=NIL OR NOT EqualModVersion[lag, name, case];
};
IF dnhlag
OR (newSeries
AND dhlag)
THEN {
IF (stopped ← NOT proc[lag]) THEN RETURN [FALSE];
};
IF lagnhps#
NIL
OR (newSeries
AND laghps#
NIL)
THEN {
WorkFrom[i+1, PSUnion[lagnhps, IF newSeries THEN laghps ELSE NIL]];
};
IF stopped THEN RETURN [FALSE];
IF dhigh
THEN {
dnhlag ← deliver OR (dlow AND newSeries);
deliver ← dlow ← FALSE}
ELSE dnhlag ← FALSE;
dhlag ← dhigh;
IF ehighps#
NIL
THEN {
lagnhps ← IF newSeries THEN PSUnion[nps, elowps] ELSE nps;
nps ← elowps ← NIL}
ELSE lagnhps ← NIL;
laghps ← ehighps;
IF deliver
OR (dlow
AND newSeries)
THEN {
IF (stopped ← NOT proc[name]) THEN RETURN [FALSE];
};
IF nps#
NIL
OR (newSeries
AND elowps#
NIL)
THEN WorkFrom[i+1, PSUnion[nps, IF newSeries THEN elowps ELSE NIL]];
lag ← name;
RETURN [NOT stopped]};
IF stopped THEN RETURN;
Process.CheckForAbort[];
[r, v, dvg, hastar] ← FindDivergence[caser, ps, i];
IF dvg
OR hastar
THEN {
stem ← ps.first.SubName[count: i+1, absolute: TRUE];
stem ← stem.ReplaceShortName[MPfsN.ConsComponent[r, v]];
IF debug THEN SF.PutFL[$MorePfs, oneLiner, $Debug, "Base enumerating %g at level %g", LIST[ [rope[PFS.RopeFromPath[stem]]], [integer[i]] ]];
base[stem, Continue, lbound, hbound !PFS.Error => CONTINUE];
IF (NOT stopped) AND (dnhlag OR dhlag) THEN stopped ← NOT proc[lag];
}
ELSE {
here, dlow, dhigh: BOOL;
nps, elowps, ehighps: PatternSet;
[,here, nps, dlow, dhigh, elowps, ehighps] ← RefinePatterns[i, ps.first.SubName[count: i+1, directory: FALSE], ps, caser];
IF here
OR dlow
OR dhigh
THEN {
ex: BOOL ← FALSE;
ex ← exists[ps.first !PFS.Error => CONTINUE];
IF ex THEN {IF NOT proc[ps.first] THEN RETURN};
};
IF nps#NIL OR elowps#NIL OR ehighps#NIL THEN WorkFrom[i+1, PSUnion[elowps, PSUnion[ehighps, nps]]];
};
RETURN};
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "Transforming enumeration of %g", [rope[PFS.RopeFromPath[pattern]]] ];
IF NOT pattern.IsAbsolute[] THEN PFS.Error[[user, $PatternNotAbsolute, IO.PutFR1["pattern %g not absolute", [rope[IF pattern=NIL THEN "<NIL>" ELSE PFS.RopeFromPath[pattern] ]] ]]];
WorkFrom[0, LIST[pattern]];
RETURN};
star: RopePart ← RP.FromChar['*];
dstar: RopePart ← RP.Make["**"];
FindDivergence:
PROC [caser: Caser, ps: PatternSet, i:
INT]
RETURNS [r: RopePart, v: Version, dvg, hastar:
BOOL ←
FALSE] ~ {
Return the most specific name and version patterns that cover the i'th component of every member of ps.
Doit:
PROC [case:
BOOL]
RETURNS [r: RopePart, v: Version, dvg, hastar:
BOOL ←
FALSE] ~ {
c: Component ← ps.first.Fetch[i];
l: INT;
clip: BOOL ← FALSE;
r ← MPfsN.ComponentName[c];
v ← c.version;
hastar ← r.Find[star]>=0;
l ← r.Length[];
FOR rps: PatternSet ← ps.rest, rps.rest
WHILE rps#
NIL
DO
thisCase: BOOL ← caser[rps.first];
thisL: INT;
thisR: RopePart;
IF thisCase AND NOT case THEN RETURN Doit[TRUE];
Process.CheckForAbort[];
c ← rps.first.Fetch[i];
IF v#c.version THEN v ← [all];
thisR ← MPfsN.ComponentName[c];
hastar ← hastar OR thisR.Find[star]>=0;
thisL ← r.Run[s2: thisR, case: case];
IF thisL<l THEN {r ← r.Substr[len: l ← thisL]; dvg ← TRUE};
IF thisL=0 AND v=[all] THEN EXIT;
ENDLOOP;
IF dvg THEN r ← r.Concat[star];
RETURN};
RETURN Doit[caser[ps.first]]};
RefinePatterns:
PROC [i:
INT, prefix:
PATH, ps: PatternSet, caser: Caser]
RETURNS [case, here:
BOOL ←
FALSE, nps: PatternSet ←
NIL, dlow, dhigh:
BOOL ←
FALSE, elowps, ehighps: PatternSet ←
NIL] ~ {
prefix is of length i+1. Return a pattern set that will match the same names that start with prefix as ps, and that includes only patterns that start with prefix. nps is the patterns that certainly match the prefix; elowps is the patterns that can only be enumerated if prefix is the lowest version; ehighps is the patterns that can only be enumerated if prefix is the highest version.
nc: Component ~ prefix.Fetch[i];
nr: RopePart ← MPfsN.ComponentName[nc];
rps: PatternSet ← ps;
dall, eall: BOOL ← FALSE;
case ← caser[prefix];
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "Refining patterns for prefix %g", [rope[PFS.RopeFromPath[prefix]]] ];
WHILE rps#
NIL
DO
pat: PATH ~ rps.first;
n: INT ~ pat.ComponentCount[];
c: Component ~ pat.Fetch[i];
r: RopePart ← MPfsN.ComponentName[c];
d: INT ← r.Find[dstar];
asRope: ROPE ← PFS.RopeFromPath[pat];
Process.CheckForAbort[];
rps ← rps.rest;
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "consuming %g", [rope[PFS.RopeFromPath[pat]]] ];
IF d>=0
THEN {
r1: RopePart ← r.Replace[d, 1];
p1: PATH ← pat.ReplaceComponent[i, MPfsN.ConsComponent[r1, c.version]];
c2a: Component ← MPfsN.ConsComponent[r.Substr[len: d+1], [all] ];
c2b: Component ← MPfsN.ConsComponent[r.Substr[start: d], c.version ];
p2a: PATH ← pat.SubName[count: i+1].ReplaceShortName[c2a];
p2b: PATH ← pat.SubName[start: i, directory: pat.IsADirectory] .ReplaceComponent[0, c2b];
p2: PATH ← p2a.Cat[p2b];
rps ← CONS[p1, CONS[p2, rps]];
IF debug THEN SF.PutFL[$MorePfs, oneLiner, $Debug, "split into %g and %g", LIST[ [rope[PFS.RopeFromPath[p1]]], [rope[PFS.RopeFromPath[p2]]] ]];
}
ELSE
IF i+1=n
THEN {
IF r.Match[nr, case]
THEN
SELECT c.version.versionKind
FROM
numeric, none => here ← nc.version = c.version;
lowest => dlow ← TRUE;
highest => dhigh ← TRUE;
all => here ← dall ← TRUE;
ENDCASE => ERROR;
}
ELSE
IF r.Match[nr, case]
THEN {
newp: PATH ~ pat.ReplaceComponent[i, nc];
SELECT c.version.versionKind
FROM
numeric, none =>
IF nc.version = c.version
THEN {
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "continuing %g", [rope[PFS.RopeFromPath[newp]]] ];
nps ← CONS[newp, nps]};
all => {
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "continuing %g", [rope[PFS.RopeFromPath[newp]]] ];
eall ← TRUE;
nps ← CONS[newp, nps]};
lowest => {
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "elow %g", [rope[PFS.RopeFromPath[newp]]] ];
elowps ← CONS[newp, elowps]};
highest => {
IF debug THEN SF.PutF[$MorePfs, oneLiner, $Debug, "ehigh %g", [rope[PFS.RopeFromPath[newp]]] ];
ehighps ← CONS[newp, ehighps]};
ENDCASE => ERROR};
ENDLOOP;
IF dall THEN dlow ← dhigh ← FALSE;
IF eall THEN elowps ← ehighps ← NIL;
RETURN};
VersionMatch:
PROC [p, o: Version, pat:
PATH]
RETURNS [
BOOL] ~ {
IF p=o THEN RETURN [TRUE];
SELECT p.versionKind
FROM
numeric, none => RETURN [FALSE];
lowest, highest, all => RETURN [TRUE];
next => ERROR PFS.Error[[user, $VersionNextInPattern, IO.PutFR1["the pattern %g has a `next' version in it", [rope[PFS.RopeFromPath[pat]]] ], pat]];
ENDCASE => ERROR};
EqualModVersion:
PROC [p1, p2:
PATH, case:
BOOL]
RETURNS [
BOOL] ~ {
n: INT ~ p1.ComponentCount[];
n2: INT ~ p2.ComponentCount[];
c1, c2: Component;
IF n#n2 THEN RETURN [FALSE];
FOR i:
INT
IN [0..n-1)
DO
c1 ← p1.Fetch[i];
c2 ← p2.Fetch[i];
IF NOT c1.EqualComponents[c2, case] THEN RETURN [FALSE];
ENDLOOP;
c1 ← p1.ShortName[];
c2 ← p2.ShortName[];
RETURN MPfsN.ComponentName[c1].Equal[MPfsN.ComponentName[c2], case]};
PSUnion:
PROC [a, b: PatternSet]
RETURNS [PatternSet] ~ {
IF b=NIL THEN RETURN [a];
FOR a ← a, a.rest WHILE a#NIL DO b ← CONS[a.first, b] ENDLOOP;
RETURN [b]};
END.