<<>> <> <> <> 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] ~ { <> <> 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 "" 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] ~ { <> 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> 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.