<> <> DIRECTORY Flow, Globals, Hash, IO, Parse, Rope; FlowImpl: CEDAR PROGRAM IMPORTS Globals, Hash, IO, Parse EXPORTS Flow = { OPEN Flow, Globals; FlowTable: PUBLIC Hash.Table _ Hash.NewTable[]; <> searchCount: INT _ 0; totalFlows: INT _ 0; <> index: INT; Mark: PUBLIC CmdProc = { Hash.Enumerate[table: NodeTable, pattern: "*", proc: markProc]; }; markProc: Hash.EnumProc = { <> n: Node _ NARROW[entry.clientData]; p: Pointer; f: 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: Node] RETURNS [result: BOOLEAN] = { <> p: Pointer; f: Fet; next: 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: Fet, name: Rope.ROPE, source: BOOLEAN] = { flow: FlowCtl; h: Hash.Entry; fp: FlowPtr; <> h _ Hash.Find[table: FlowTable, name: name]; IF h.clientData = NIL THEN { flow _ NEW[FlowRec _ [name, NIL, NIL, FALSE, FALSE, FALSE, FALSE]]; h.clientData _ flow; totalFlows _ totalFlows + 1; } ELSE flow _ NARROW[h.clientData]; <> fp _ NEW[FlowPtrRec _ [flow, fet.firstFlow, source, NOT source]]; fet.firstFlow _ fp; }; Lock: PUBLIC PROC[fet: Fet, input: Node] RETURNS [BOOLEAN] = { fp: FlowPtr; flow: 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: Fet, input: Node] = { fp: FlowPtr; flow: 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 CmdProc = { names: ARRAY[0..5) OF Rope.ROPE _ [ "ignore", "in", "normal", "off", "out" ]; IF args = NIL THEN { IO.PutRope[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[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: StdOut]; args _ args.next; ENDLOOP; }; flowProc: Hash.EnumProc = { flow: 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[StdOut, "Total number of flows: %d.\n", IO.int[totalFlows]]; IO.PutF[StdOut, "Total number of calls during flow marking: %d.\n", IO.int[searchCount]]; }; }.