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: BOOLTRUE;
EnumerateForNames: PUBLIC Enumerator ~ {
TransformEnumerator[PFS.EnumerateForNames, PfsCaser, PfsETester, pattern, proc, lbound, hbound];
RETURN};
EnumerateForInfo: PUBLIC PROC [pattern: PATH, proc: InfoProc, lbound: PATHNIL, hbound: PATHNIL ] ~ {
PerName: PROC [name: PATH] RETURNS [continue: BOOLTRUE] ~ {
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: BOOLFALSE] ~ {
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: PATHNIL, hbound: PATHNIL ] ~ {
stopped: BOOLFALSE;
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: PATHNIL;
laghps, lagnhps: PatternSet ← NIL;
dhlag, dnhlag: BOOLFALSE;
Continue: NameProc ~ {
case, deliver, dlow, dhigh, newSeries: BOOLFALSE;
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: BOOLFALSE;
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: BOOLFALSE] ~ {
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: BOOLFALSE] ~ {
c: Component ← ps.first.Fetch[i];
l: INT;
clip: BOOLFALSE;
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: BOOLFALSE, nps: PatternSet ← NIL, dlow, dhigh: BOOLFALSE, 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: BOOLFALSE;
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: ROPEPFS.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.