<> <> <> DIRECTORY Flow, Globals, Hash, HashTable, IO, Parse, Rope; FlowImpl: CEDAR PROGRAM IMPORTS Globals, Hash, HashTable, IO, Parse EXPORTS Flow = { OPEN Flow; FlowTable: PUBLIC Hash.Table _ Hash.NewTable[]; <> searchCount: INT _ 0; totalFlows: INT _ 0; <> index: INT; Mark: PUBLIC Globals.CmdProc = { <> [] _ HashTable.Pairs[globalVars.nodeTable, MarkProc]; }; MarkProc: HashTable.EachPairAction = { <> n: Globals.Node _ NARROW[value]; p: Globals.Pointer; f: Globals.Fet; IF n.output THEN { [] _ checkFlowTo[n]; RETURN; }; IF n.input THEN RETURN; FOR p _ n.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; IF (f.gate = n) AND (f.source # n) AND (f.drain # n) THEN { [] _ checkFlowTo[n]; RETURN; }; ENDLOOP; }; checkFlowTo: PROC[node: Globals.Node] RETURNS [result: BOOLEAN] = { <> p: Globals.Pointer; f: Globals.Fet; next: Globals.Node; fromDrain: BOOLEAN; searchCount _ searchCount + 1; <> node.inPath _ TRUE; result _ FALSE; FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; <> IF f.source = node THEN { next _ f.drain; fromDrain _ TRUE; IF f.flowFromDrain THEN { result _ TRUE; LOOP; }; IF f.noDrainInfo THEN LOOP; } ELSE IF f.drain = node THEN { next _ f.source; fromDrain _ FALSE; IF f.flowFromSource THEN { result _ TRUE; LOOP; }; IF f.noSourceInfo THEN LOOP; } ELSE LOOP; <> IF next.inPath THEN LOOP; <> IF NOT next.input THEN IF NOT checkFlowTo[next] THEN LOOP; IF fromDrain THEN f.flowFromDrain _ TRUE ELSE f.flowFromSource _ TRUE; result _ TRUE; ENDLOOP; node.inPath _ FALSE; RETURN [result]; }; Build: PUBLIC PROC[fet: Globals.Fet, name: Rope.ROPE, source: BOOLEAN] = { flow: Globals.FlowCtl; h: Hash.Entry; fp: Globals.FlowPtr; <> h _ Hash.Find[table: FlowTable, name: name]; IF h.clientData = NIL THEN { flow _ NEW[Globals.FlowRec _ [name, NIL, NIL, FALSE, FALSE, FALSE, FALSE]]; h.clientData _ flow; totalFlows _ totalFlows + 1; } ELSE flow _ NARROW[h.clientData]; <> fp _ NEW[Globals.FlowPtrRec _ [flow, fet.firstFlow, source, NOT source]]; fet.firstFlow _ fp; }; Lock: PUBLIC PROC[fet: Globals.Fet, input: Globals.Node] RETURNS [BOOLEAN] = { fp: Globals.FlowPtr; flow: Globals.FlowCtl; IF (input # fet.source) AND (input # fet.drain) THEN RETURN [TRUE]; <> FOR fp _ fet.firstFlow, fp.next UNTIL fp = NIL DO flow _ fp.flow; IF flow.ignore THEN LOOP; IF flow.off THEN RETURN [FALSE]; IF ((input = fet.source) AND fp.source) OR ((input = fet.drain) AND fp.drain) THEN { IF flow.outOnly THEN RETURN [FALSE]; IF flow.left # NIL THEN RETURN [FALSE]; } ELSE { IF flow.inOnly THEN RETURN [FALSE]; IF flow.entered # NIL THEN RETURN [FALSE]; }; ENDLOOP; <> FOR fp _ fet.firstFlow, fp.next UNTIL fp = NIL DO flow _ fp.flow; IF ((input = fet.source) AND fp.source) OR ((input = fet.drain) AND fp.drain) THEN { IF flow.entered = NIL THEN flow.entered _ input; } ELSE { IF flow.left = NIL THEN flow.left _ input; }; ENDLOOP; RETURN [TRUE]; }; Unlock: PUBLIC PROC[fet: Globals.Fet, input: Globals.Node] = { fp: Globals.FlowPtr; flow: Globals.FlowCtl; FOR fp _ fet.firstFlow, fp.next UNTIL fp = NIL DO flow _ fp.flow; IF flow.entered = input THEN flow.entered _ NIL; IF flow.left = input THEN flow.left _ NIL; ENDLOOP; }; FlowCmd: PUBLIC Globals.CmdProc = { names: ARRAY[0..5) OF Rope.ROPE _ [ "ignore", "in", "normal", "off", "out" ]; IF args = NIL THEN { IO.PutRope[Globals.StdOut, "No keyword given: try ignore, off, in, out, or normal.\n"]; RETURN; }; TRUSTED {index _ Parse.Lookup[args.rope, DESCRIPTOR[names]]}; IF index < 0 THEN { IO.PutRope[Globals.StdOut, "Bad keyword, try ignore, off, in, out, or normal.\n"]; RETURN; }; args _ args.next; <> WHILE args # NIL DO Hash.Enumerate[table: FlowTable, pattern: args.rope, proc: flowProc, errorStream: Globals.StdOut]; args _ args.next; ENDLOOP; }; flowProc: Hash.EnumProc = { flow: Globals.FlowCtl _ NARROW[entry.clientData]; flow.inOnly _ FALSE; flow.outOnly _ FALSE; flow.off _ FALSE; flow.ignore _ FALSE; SELECT index FROM 0 => flow.ignore _ TRUE; 1 => flow.inOnly _ TRUE; 3 => flow.off _ TRUE; 4 => flow.outOnly _ TRUE; ENDCASE; }; Stats: PUBLIC PROC[] = { IO.PutF[Globals.StdOut, "Total number of flows: %d.\n", IO.int[totalFlows]]; IO.PutF[Globals.StdOut, "Total number of calls during flow marking: %d.\n", IO.int[searchCount]]; }; }.