<> <> <> <> <> <<>> DIRECTORY NodeProps, TextNode, PGSupport, RefTab, NameSymbolTable, Rope; NodePropsImpl: CEDAR PROGRAM IMPORTS NameSymbolTable, RefTab, Rope, TextNode EXPORTS TextNode, NodeProps = BEGIN OPEN NodeProps; Prop, Props: TYPE = REF NodePropsBody; NodePropsBody: PUBLIC TYPE = RECORD [ name: ATOM, -- name of the property next: Props, -- points to next property value: REF ]; commentAtom: ATOM = $Comment; commentName: ROPE = "Comment"; typeAtom: ATOM = $Format; typeName: ROPE = "Format"; styleDefAtom: ATOM = $StyleDef; styleDefName: ROPE = "StyleDef"; prefixAtom: ATOM = $Prefix; prefixName: ROPE = "Prefix"; postfixAtom: ATOM = $Postfix; postfixName: ROPE = "Postfix"; ObjectRec: TYPE = RECORD [rope: ROPE, object: Object]; true: PUBLIC REF BOOLEAN _ NEW[BOOLEAN _ TRUE]; false: PUBLIC REF BOOLEAN _ NEW[BOOLEAN _ FALSE]; ReadComment: PROC [name: ATOM, specs: ROPE] RETURNS [value: REF] = { RETURN [IF Rope.Equal[specs,"TRUE",FALSE] THEN true ELSE false] }; WriteComment: PROC [name: ATOM, value: REF] RETURNS [specs: ROPE] = { specs _ "FALSE"; IF value # NIL THEN WITH value SELECT FROM x: REF BOOLEAN => IF x^ THEN specs _ "TRUE"; ENDCASE }; CopyComment, CopyPfix: PROC [name: ATOM, value: REF] RETURNS [new: REF] = { RETURN [value] }; ReadPfix: PROC [name: ATOM, specs: ROPE] RETURNS [value: REF] = { RETURN [specs] }; WritePfix: PROC [name: ATOM, value: REF] RETURNS [specs: ROPE] = { RETURN [NARROW[value]] }; PrefixName: PUBLIC PROC RETURNS [ROPE] = { RETURN [prefixName] }; PrefixAtom: PUBLIC PROC RETURNS [ATOM] = { RETURN [prefixAtom] }; PostfixName: PUBLIC PROC RETURNS [ROPE] = { RETURN [postfixName] }; PostfixAtom: PUBLIC PROC RETURNS [ATOM] = { RETURN [postfixAtom] }; GetPrefixObject: PUBLIC PROCEDURE [n: TextNode.Ref] RETURNS [ob: Object] = { RETURN [GetPFix[n,prefixAtom]] }; GetPostfixObject: PUBLIC PROCEDURE [n: TextNode.Ref] RETURNS [ob: Object] = { RETURN [GetPFix[n,postfixAtom]] }; GetPFix: PROC [n: TextNode.Ref, name: ATOM] RETURNS [Object] = { prop: Prop _ FindName[n, name, FALSE]; val: REF ObjectRec; IF prop=NIL OR (val _ NARROW[prop.value])=NIL THEN RETURN [NameSymbolTable.NullObject[]]; RETURN [val.object] }; FindName: PROC [n: TextNode.Ref, name: ATOM, remove: BOOLEAN] RETURNS [prop: Prop] = { lst, prev: Props; IF n=NIL THEN RETURN [NIL]; lst _ n.props; prop _ NIL; prev _ NIL; WHILE lst#NIL DO IF lst.name = name THEN { prop _ lst; EXIT }; prev _ lst; lst _ lst.next; ENDLOOP; IF prop#NIL AND remove THEN IF prev#NIL THEN prev.next _ prop.next ELSE n.props _ prop.next }; PutProp: PUBLIC PROCEDURE [n: TextNode.Ref, name: ATOM, value: REF] = { prop: Prop _ FindName[n, name, FALSE]; PFix: PROC = TRUSTED { rope: ROPE _ NARROW[value]; -- value is rope for the prefix/postfix ob: Object _ NameSymbolTable.MakeObject[LOOPHOLE[Rope.Flatten[rope]]]; value _ TextNode.pZone.NEW[ObjectRec _ [rope, ob]] }; IF value = NIL THEN { IF prop#NIL THEN prop.value _ NIL; SELECT name FROM styleDefAtom => n.hasstyledef _ FALSE; prefixAtom => n.hasprefix _ FALSE; postfixAtom => n.haspostfix _ FALSE; typeAtom => n.typename _ TextNode.nullTypeName; commentAtom => { txt: TextNode.RefTextNode _ TextNode.NarrowToTextNode[n]; IF txt#NIL THEN txt.comment _ FALSE }; ENDCASE; RETURN }; SELECT name FROM styleDefAtom => n.hasstyledef _ TRUE; prefixAtom => { PFix; n.hasprefix _ TRUE }; postfixAtom => { PFix; n.haspostfix _ TRUE }; typeAtom => { WITH value SELECT FROM x: Rope.ROPE => TRUSTED {n.typename _ NameSymbolTable.MakeName[LOOPHOLE[Rope.Flatten[x]]]}; ENDCASE => ERROR; RETURN }; commentAtom => { -- simply set the bit in the node txt: TextNode.RefTextNode _ TextNode.NarrowToTextNode[n]; WITH value SELECT FROM x: REF BOOLEAN => txt.comment _ x^; ENDCASE => ERROR; RETURN }; ENDCASE; IF prop#NIL THEN { prop.value _ value; RETURN }; n.props _ TextNode.pZone.NEW[NodePropsBody _ [name, n.props, value]] }; GetProp: PUBLIC PROCEDURE [n: TextNode.Ref, name: ATOM] RETURNS [value: REF] = { prop: Prop _ FindName[n, name, FALSE]; PFix: PROC RETURNS [REF] = { val: REF ObjectRec _ NARROW[prop.value]; RETURN [IF val=NIL THEN NIL ELSE val.rope] }; IF prop # NIL THEN SELECT name FROM prefixAtom, postfixAtom => value _ PFix[]; ENDCASE => value _ prop.value ELSE IF name = commentAtom THEN { txt: TextNode.RefTextNode _ TextNode.NarrowToTextNode[n]; value _ IF txt # NIL AND txt.comment THEN true ELSE false } ELSE IF name = typeAtom THEN value _ IF n.typename = TextNode.nullTypeName THEN NIL ELSE NameSymbolTable.RopeFromName[n.typename] }; RemProp: PUBLIC PROCEDURE [n: TextNode.Ref, name: ATOM] = { [] _ FindName[n, name, TRUE]; -- removes the value SELECT name FROM styleDefAtom => n.hasstyledef _ FALSE; prefixAtom => n.hasprefix _ FALSE; postfixAtom => n.haspostfix _ FALSE; typeAtom => n.typename _ TextNode.nullTypeName; commentAtom => { txt: TextNode.RefTextNode _ TextNode.NarrowToTextNode[n]; IF txt#NIL THEN txt.comment _ FALSE }; ENDCASE }; MapProps: PUBLIC PROCEDURE [n: TextNode.Ref, action: MapPropsAction, typeFlag, commentFlag: BOOLEAN _ TRUE] RETURNS [BOOLEAN] = { <> <> props: Props; next: Props; name: ATOM; value: REF; txt: TextNode.RefTextNode; IF n=NIL THEN RETURN [FALSE]; props _ n.props; IF typeFlag AND action[typeAtom,NameSymbolTable.RopeFromName[n.typename]] THEN RETURN [TRUE]; IF commentFlag AND (txt _ TextNode.NarrowToTextNode[n]) # NIL THEN IF action[commentAtom,IF txt.comment THEN true ELSE false] THEN RETURN [TRUE]; WHILE props#NIL DO next _ props.next; -- get it now in case action deletes current prop SELECT name _ props.name FROM prefixAtom, postfixAtom => { x: REF ObjectRec _ NARROW[props.value]; value _ IF x=NIL THEN NIL ELSE x.rope }; ENDCASE => value _ props.value; IF action[name,value] THEN RETURN [TRUE]; props _ next; ENDLOOP; RETURN [FALSE]}; <<-- ***** read, write, copy props>> ReaderProcRef: TYPE = REF ReaderProcRec; ReaderProcRec: TYPE = RECORD [proc: ReadSpecsProc]; WriterProcRef: TYPE = REF WriterProcRec; WriterProcRec: TYPE = RECORD [proc: WriteSpecsProc]; CopierProcRef: TYPE = REF CopierProcRec; CopierProcRec: TYPE = RECORD [proc: CopyInfoProc]; readerTable: RefTab.Ref _ RefTab.Create[]; writerTable: RefTab.Ref _ RefTab.Create[]; copierTable: RefTab.Ref _ RefTab.Create[]; Register: PUBLIC PROC [name: ATOM, reader: ReadSpecsProc, writer: WriteSpecsProc, copier: CopyInfoProc] = { <<-- registers these procs for this variety of node>> <<-- they will be called by DoSpecs, GetSpecs, and CopyInfo >> IF name=NIL THEN RETURN; [] _ RefTab.Store[readerTable,name,TextNode.pZone.NEW[ReaderProcRec _ [reader]]]; [] _ RefTab.Store[writerTable,name,TextNode.pZone.NEW[WriterProcRec _ [writer]]]; [] _ RefTab.Store[copierTable,name,TextNode.pZone.NEW[CopierProcRec _ [copier]]] }; NullRead: PUBLIC PROC [name: ATOM, specs: ROPE] RETURNS [value: REF] = { RETURN [NIL] }; NullWrite: PUBLIC PROC [name: ATOM, value: REF] RETURNS [specs: ROPE] = { RETURN [NIL] }; NullCopy: PUBLIC PROC [name: ATOM, value: REF] RETURNS [new: REF] = { RETURN [NIL] }; DoSpecs: PUBLIC PROC [name: ATOM, specs: ROPE] RETURNS [value: REF] = { <<-- used when reading files>> <<-- calls the registered reader for this property name>> <<-- returns specs if no reader is registered>> procRef: ReaderProcRef; proc: ReadSpecsProc; value _ IF name=NIL OR (procRef _ NARROW[RefTab.Fetch[readerTable,name].val])=NIL OR (proc _ procRef.proc)=NIL THEN specs ELSE proc[name,specs] }; GetSpecs: PUBLIC PROC [name: ATOM, value: REF] RETURNS [specs: ROPE] = { <<-- used when writing files>> <<-- calls the registered writer for this property name>> <<-- if no writer is registered, returns value if it is a rope, NIL otherwise>> procRef: WriterProcRef; proc: WriteSpecsProc; IF name=NIL OR (procRef _ NARROW[RefTab.Fetch[writerTable,name].val])=NIL OR (proc _ procRef.proc)=NIL THEN IF value=NIL THEN specs _ NIL ELSE WITH value SELECT FROM rope: ROPE => specs _ rope; ENDCASE => specs _ NIL ELSE specs _ proc[name,value] }; CopyInfo: PUBLIC PROC [name: ATOM, value: REF] RETURNS [new: REF] = { <<-- used when copying nodes>> <<-- calls the registered copier for this property name>> <<-- if no copier is registered, returns value>> procRef: CopierProcRef; proc: CopyInfoProc; new _ IF name=NIL OR (procRef _ NARROW[RefTab.Fetch[copierTable,name].val])=NIL OR (proc _ procRef.proc)=NIL THEN value ELSE proc[name,value] }; <<-- ***** Initialization>> StartNodeProps: PUBLIC PROC = { Register[prefixAtom, ReadPfix, WritePfix, CopyPfix]; Register[postfixAtom, ReadPfix, WritePfix, CopyPfix]; Register[commentAtom, ReadComment, WriteComment, CopyComment] }; END.