DIRECTORY IO USING [atom, BreakProc, EndOfStream, GetTokenRope, IDProc, PutFR, RIS, rope, STREAM], LoganBerry USING [AttributeType, AttributeValue, Entry, Error, Open], LoganQuery USING [AttributePatterns, ComplexCursor, NextEntry, QueryEntries, ReadAttributePatterns, SyntaxError], NodeProps USING [GetProp, PutProp], Rope USING [Cat, Concat, ROPE, Size], TextLooks USING [CreateRun], TextNode USING [Body, Ref], TextNodeRegistry USING [ActivityProc, ProcSetRec, Register, SizeProc, TransformProc]; QueryNodeRegister: CEDAR MONITOR IMPORTS IO, LoganBerry, LoganQuery, NodeProps, Rope, TextLooks, TextNodeRegistry = BEGIN ROPE: TYPE ~ Rope.ROPE; Ref: TYPE ~ TextNode.Ref; lastq: Ref _ NIL; cursor: REF LoganQuery.ComplexCursor _ NIL; FormatProc: TYPE ~ PROC [entry: LoganBerry.Entry] RETURNS [rope: ROPE]; QueryToText: ENTRY PROC [q, p, s: Ref _ NIL, fproc: FormatProc] RETURNS [t: Ref] ~ { ENABLE LoganBerry.Error => { q.rope _ IO.PutFR["%g\n%g - %g", IO.rope[q.rope], IO.atom[ec], IO.rope[explanation]]; q.runs _ TextLooks.CreateRun[Rope.Size[q.rope]]; GOTO QueryCompleted }; entry: LoganBerry.Entry; IF q=NIL THEN RETURN[NIL]; IF q # lastq THEN { -- get new cursor lastq _ q; cursor _ NARROW[NodeProps.GetProp[q, $LBCursor]]; IF cursor = NIL THEN cursor _ QueryToCursor[q]; IF cursor = NIL THEN GOTO QueryCompleted; }; entry _ LoganQuery.NextEntry[cursor: cursor^]; IF entry = NIL THEN GOTO QueryCompleted; t _ NEW[TextNode.Body _ q^]; -- t inherits q's properties t.child _ NIL; t.last _ FALSE; t.rope _ fproc[entry]; t.runs _ TextLooks.CreateRun[Rope.Size[t.rope]]; t.next _ q; IF s=NIL THEN { IF p=NIL THEN { p _ q; WHILE NOT p.last DO p _ p.next; ENDLOOP; p _ p.next; -- p is now q's parent }; IF p.child#q THEN { s _ p.child; -- get to first sibling WHILE s.next # q DO s _ s.next; ENDLOOP; }; }; IF s#NIL THEN s.next _ t ELSE p.child _ t; EXITS QueryCompleted => { NodeProps.PutProp[q, $Active, NIL]; -- make node inactive RETURN[NIL]; }; }; QueryToCursor: PROC [q: Ref] RETURNS [cursor: REF LoganQuery.ComplexCursor] ~ { query: ROPE = q.rope; cursor _ InitiateQuery[query]; q.rope _ IF cursor = NIL THEN Rope.Concat["Bad Query: ", query] ELSE NIL; q.runs _ TextLooks.CreateRun[Rope.Size[q.rope]]; NodeProps.PutProp[q, $LBCursor, cursor]; }; InitiateQuery: PROC [rope: Rope.ROPE] RETURNS [c: REF LoganQuery.ComplexCursor] ~ { dbname: Rope.ROPE; ap: LoganQuery.AttributePatterns; s: IO.STREAM _ IO.RIS[rope]; dbname _ IO.GetTokenRope[s, IO.IDProc ! IO.EndOfStream => GOTO End].token; ap _ LoganQuery.ReadAttributePatterns[s ! LoganQuery.SyntaxError => GOTO End]; c _ NEW[LoganQuery.ComplexCursor _ LoganQuery.QueryEntries[db: LoganBerry.Open[dbName: dbname], patterns: ap].cursor]; EXITS End => RETURN[NIL]; }; EntryToRope: FormatProc ~ { rope _ NIL; FOR l: LoganBerry.Entry _ entry, l.rest WHILE l # NIL DO rope _ IO.PutFR["%g%g: %g\n", IO.rope[rope], IO.atom[l.first.type], IO.rope[l.first.value]]; ENDLOOP; }; LBQueryTransform: TextNodeRegistry.TransformProc = { new _ QueryToText[node, parent, NIL, EntryToRope]; IF new=NIL THEN RETURN[node]; IF NOT wantFirst THEN { last: Ref _ new; WHILE last # NIL DO new _ last; last _ QueryToText[node, parent, last, EntryToRope]; ENDLOOP; }; }; LBQuerySize: TextNodeRegistry.SizeProc = { RETURN[300]; -- a *rough* estimate }; tName: LoganBerry.AttributeType = $name; tRname: LoganBerry.AttributeType = $rname; tOffice: LoganBerry.AttributeType = $officenumber; tHome: LoganBerry.AttributeType = $homenumber; tRemarks: LoganBerry.AttributeType = $remarks; LBToTDirEntry: FormatProc ~ { GetAttributeValue: PROC [entry: LoganBerry.Entry, type: LoganBerry.AttributeType] RETURNS [LoganBerry.AttributeValue] ~ { FOR e: LoganBerry.Entry _ entry, e.rest WHILE e # NIL DO IF e.first.type = type THEN RETURN[e.first.value]; ENDLOOP; RETURN[NIL]; }; val: Rope.ROPE; rope _ GetAttributeValue[entry, tName]; val _ GetAttributeValue[entry, tRname]; IF val # NIL THEN rope _ Rope.Cat[rope, " <", val, ">"]; val _ GetAttributeValue[entry, tOffice]; rope _ Rope.Cat[rope, "\t", IF val = NIL THEN "*" ELSE val]; val _ GetAttributeValue[entry, tHome]; rope _ Rope.Cat[rope, "\t", IF val = NIL THEN "*" ELSE val]; val _ GetAttributeValue[entry, tRemarks]; IF val # NIL THEN rope _ Rope.Cat[rope, "\t", val]; }; WPQueryTransform: TextNodeRegistry.TransformProc = { new _ QueryToText[node, parent, NIL, LBToTDirEntry]; IF new=NIL THEN RETURN[node]; IF NOT wantFirst THEN { last: Ref _ new; WHILE last # NIL DO new _ last; last _ QueryToText[node, parent, last, LBToTDirEntry]; ENDLOOP; }; }; WPQuerySize: TextNodeRegistry.SizeProc = { RETURN[300]; -- a *rough* estimate }; TextNodeRegistry.Register[activity: $LBQuery, procs: NEW[TextNodeRegistry.ProcSetRec _ [activityOn: TRUE, transformProc: LBQueryTransform, sizeProc: LBQuerySize, activityProc: NIL]]]; TextNodeRegistry.Register[activity: $WPQuery, procs: NEW[TextNodeRegistry.ProcSetRec _ [activityOn: TRUE, transformProc: WPQueryTransform, sizeProc: WPQuerySize, activityProc: NIL]]]; END. .QueryNodeRegister.mesa Copyright Σ 1985, 1986 by Xerox Corporation. All rights reserved. Doug Terry, July 28, 1987 11:11:29 am PDT This allows active Tioga documents that retrieve nodes from a LoganBerry database as they are requested. Nodes with the value "LBQuery" for the "Active" property are dynamically replaced with the results obtained from running the query specified by the node's contents. The query need not always be run in its entirety; in many cases the query node can be replaced by two nodes: the first being the first database entry returned by the query and the second being a new query (specifcally a database cursor) to generate the remaining entries. remember last query and its cursor to improve performance Note: There should be a timeout on QueryToText to avoid long waits. On input: q should be a node with Active property $LBQuery, p (if not NIL) should be q's parent, s (if not NIL) should be q's preceeding sibling, Note that p and s can be determined given q so their input is only for performance improvement. Upon completion: t is a text node containing the first database entry obtained by running the query specified in q (or NIL if no such entry), t.next is a $LBQuery node representing the rest of the query that remains to be run. Get next entry returned by query Create new node t for returned entry Link t before q in tree Active=LBQuery [entry: LoganBerry.Entry] RETURNS [rope: ROPE] [node: TextNode.Ref, parent: TextNode.Ref, wantFirst: BOOLEAN, clientData: REF ANY] RETURNS [new: TextNode.Ref] the query specified in q must be completely processed; new will be the last node in the list of retrieved database entries. [node: TextNode.Ref, clientData: REF ANY] RETURNS [size: INT] Active=WPQuery [entry: LoganBerry.Entry] RETURNS [rope: ROPE] [node: TextNode.Ref, parent: TextNode.Ref, wantFirst: BOOLEAN, clientData: REF ANY] RETURNS [new: TextNode.Ref] the query specified in q must be completely processed; new will be the last node in the list of retrieved database entries. [node: TextNode.Ref, clientData: REF ANY] RETURNS [size: INT] Κ g˜codešœ™KšœB™BK™)—K™šœŸ™ŸK™—šΟk ˜ Kšœœ;œœ˜XKšœ œ5˜EKšœ œa˜qKšœ œ˜#Kšœœ œ ˜&Kšœ œ ˜Kšœ œ ˜Kšœœ?˜U—K˜KšΠblœœ˜ KšœI˜Pšœ˜K˜Kšœœœ˜šœœ˜K˜—Kšœ9™9Kšœ œ˜Kšœœœ˜+K˜K™CK˜Kš œ œœœœ˜GK˜šΟn œ œœœ ˜TK™ςK™βšœ˜Kš œ œœœ œ˜VKšœ0˜1Kšœ˜Kšœ˜—K˜Kš œœœœœ˜K™ šœ œΟc˜&Kšœ ˜ Kšœ œ"˜1šœ œœ˜Kšœ˜—Kšœ œœœ˜)K˜—Kšœ.˜.Kšœ œœœ˜(K™$Kšœœ ˜:Kšœ œ˜Kšœ œ˜Kšœ˜K˜0K™K˜ šœœœ˜šœœœ˜K˜Kšœœœ œ˜(Kšœ  ˜#Kšœ˜—šœ œ˜Kšœ ˜%Kšœ œ œ˜(K˜—K˜—šœ˜Kšœ ˜Kšœ ˜—š˜šœ˜Kšœœ ˜:Kšœœ˜ K˜——K˜K˜—šŸ œœ œ œ˜OKšœœ ˜Kšœ˜Kš œ œ œœ#œœ˜IKšœ0˜0Kšœ(˜(K˜—K˜š Ÿ œœ œœœ˜SKšœ œ˜Kšœ!˜!Kš œœœœœ˜Kš œ œœ œœ ˜JKšœDœ˜NKšœœo˜vš˜Kšœœœ˜—K˜K˜——headšœ™šŸ œ˜Kšœœœ™.Kšœœ˜ šœ%œœ˜8Kš œœœ œœ˜\Kšœ˜—K˜K˜—•StartOfExpansions -- [node: TextNode.Ref, parent: TextNode.Ref, wantFirst: BOOLEAN, clientData: REF ANY] RETURNS [new: TextNode.Ref]šŸœ$˜4Kš œ6œœœœ™oKšœ œ ˜2Kšœœœœ˜šœœ œ˜K™{K˜šœœ˜K˜ Kšœ4˜4Kšœ˜—K˜—K˜K˜—–A -- [node: TextNode.Ref, clientData: REF ANY] RETURNS [size: INT]šŸ œ˜*Kš œ!œœœœ™=K–-[message: ROPE, clearFirst: BOOL _ FALSE]šœ ˜#K˜K˜——šœ™Kšœ(˜(Kšœ*˜*Kšœ2˜2Kšœ.˜.Kšœ.˜.K˜šΟb œ˜Kšœœœ™.šŸœœ;œ ˜yšœ%œœ˜8šœ˜Kšœ˜—Kšœ˜—Kšœœ˜ K˜—Kšœ œ˜Kšœ'˜'Kšœ'˜'šœœ˜Kšœ&˜&—Kšœ(˜(Kš œœœœœ˜