<> <> <> DIRECTORY BtoT, UserExec, Rope, FileIO, IO, SafeStorage, TiogaFileOps; BravoToTioga: CEDAR PROGRAM IMPORTS R: Rope, FileIO, IO, T: TiogaFileOps, UserExec EXPORTS BtoT = { ROPE: TYPE = R.ROPE; RCList: TYPE = LIST OF RECORD[coms: CList, span: INT]; CList: TYPE = LIST OF CHAR; Font: ARRAY CHAR['1..'9] OF CHAR = ['s, , 'm, 'g, 'l, 'o, , 'f, 'x]; BtoTError: ERROR[c: CHAR, s1, s2: ROPE] = CODE; Command: UserExec.CommandProc = { in: IO.STREAM _ IO.CreateInputStreamFromRope[event.commandLine]; fileName: ROPE _ in.GetToken[]; outputName: ROPE _ NIL; outputName _ in.GetToken[! IO.EndOfStream => CONTINUE]; IF outputName.Equal["_"] THEN { outputName _ fileName; fileName _ in.GetToken[! IO.EndOfStream => CONTINUE]; }; msg _ IF fileName.Length[] > 0 THEN IO.PutFToRope["%g written.\n", IO.rope[BravoToTioga[fileName, outputName]]] ELSE "Empty file name.\n"; }; ParseLine: PROC [line: ROPE] RETURNS [content: ROPE, paragraphData: ROPE, runCoding: ROPE] = { contentEnd, pdStart, pEnd, rcStart: INT _ line.Length[]; State: TYPE = {inContent, inParagraphData, inRunCoding}; state: State _ inContent; loc: INT _ 0; Action: PROC [c: CHAR] RETURNS [BOOL_FALSE] = { SELECT state FROM inContent => IF c=R.Control['Z] THEN {contentEnd _ loc; pdStart _ loc+1; state _ inParagraphData}; inParagraphData => IF c='\\ THEN {pEnd _ loc; rcStart _ loc+1; state _ inRunCoding}; inRunCoding => NULL; ENDCASE => ERROR; loc _ loc+1; }; [] _ line.Map[action: Action]; content _ line.Substr[start: 0, len: contentEnd]; paragraphData _ line.Substr[start: pdStart, len: pEnd-pdStart]; runCoding _ line.Substr[start: rcStart]; }; GetInt: PROC[stream: IO.STREAM] RETURNS [value: INT _ 0] = { WHILE NOT stream.EndOf[] AND stream.PeekChar[] IN ['0..'9] DO value _ value * 10 + (stream.GetChar[] - '0); ENDLOOP; }; BravoToTioga: PUBLIC PROC[fileName: ROPE, outputName: ROPE _ NIL] RETURNS[actualOutputName: ROPE] = { st: IO.Handle; ParentStack: ARRAY [0..10) OF RECORD[node: T.Ref]; psp: [0..10) _ 0; root: T.Ref; node: T.Ref; rootName: ROPE; DotPos: INT = fileName.SkipTo[0, "."]; IF DotPos=fileName.Length[] THEN {rootName _ fileName; fileName _ fileName.Cat[".bravo"]} ELSE rootName _ fileName.Substr[0, DotPos]; actualOutputName _ IF outputName=NIL THEN rootName.Cat[".tioga"] ELSE outputName; st _ FileIO.Open[fileName, read]; root _ T.CreateRoot[]; T.SetStyle[root, "Cedar"]; node _ root; ParentStack[0] _ [root]; UNTIL st.EndOf[] DO newIndent: INT; GetNum: PROC [keyChar: CHAR, default: INT _ 0] RETURNS [INT] = { FOR j: INT IN [0..p.Length) DO IF p.Fetch[j] = keyChar THEN { value: INT _ 0; FOR k: INT IN [j+1..p.Length) DO digit: CHAR _ p.Fetch[k]; IF digit IN ['0..'9] THEN value _ value * 10 + (digit-'0) ELSE EXIT; ENDLOOP; RETURN[value]; }; ENDLOOP; RETURN[default] }; c, p, r: ROPE; [content: c, paragraphData: p, runCoding: r] _ ParseLine[IO.GetSequence[st]]; newIndent _ MIN[psp+1, GetNum['l, 3000]/(2540/2)]; <> <> IF st.PeekChar[] = IO.CR THEN [] _ st.GetChar[]; UNTIL psp<=1 OR newIndent >= psp DO psp _ psp-1 ENDLOOP; IF newIndent>psp THEN { psp _ psp+1; ParentStack[psp] _ [node _ T.InsertNode[ParentStack[psp-1].node, TRUE]] } ELSE { ParentStack[psp].node _ node _ T.InsertNode[ParentStack[psp].node, FALSE] }; T.SetContents[node, c]; T.SetFormat[node, "indent"]; {here: INT _ 0; FOR l: RCList _ ParseRC[r, c.Length[]], l.rest UNTIL l=NIL DO c: CList _ l.first.coms; UNTIL c=NIL DO SELECT c.first FROM 'f => {d: CHAR = c.rest.first; c _ c.rest; IF d='2 THEN {T.SetFormat[node, "logo"]} ELSE IF d='7 THEN {x: INT = ComputeRun[l, 'f]; T.AddLooks[node, here, x, 'o, root]; T.AddLooks[node, here, x, 's, root]} ELSE IF d#'0 THEN {T.AddLooks[node, here, ComputeRun[l, 'f], Font[d], root]}}; 't, 'o => c _ c.rest; 'b, 'i, 'z => {T.AddLooks[node, here, ComputeRun[l, R.Upper[c.first]], c.first, root]}; 'u, 'd => {T.AddLooks[node, here, ComputeRun[l, 'D], c.first, root]}; ENDCASE; c _ c.rest; ENDLOOP; here _ here + l.first.span; ENDLOOP}; ENDLOOP; {T.Store[root, actualOutputName]}; st.Close[]; }; ParseRC: PROC[r: ROPE, l: INT] RETURNS[RCList] = {ms: IO.STREAM _ IO.CreateInputStreamFromRope[r]; P: PROC RETURNS [RCList] = {IF ms.EndOf[] THEN RETURN [NIL]; {c: CList = GetComs[]; i: INT = GetSpan[]; RETURN[CONS[[c, i], P[]]]}}; GetComs: PROC RETURNS [CList] = {IF ms.EndOf[] THEN RETURN[NIL]; SELECT ms.PeekChar[] FROM 'o => {[] _ ms.GetChar[]; {n: INT = GetInt[ms]; -- n>128 implies subscript, n=0 implies neither RETURN[CONS[(IF n=0 THEN 'D ELSE IF n>128 THEN 'd ELSE 'u), GetComs[]]]}}; 'f, 't=> {RETURN[CONS[ms.GetChar[], CONS[ms.GetChar[], GetComs[]]]]}; 'b, 'i, 'B, 'I, 'v, 'V, 'g, 'G, 's, 'S => {RETURN[CONS[ms.GetChar[], GetComs[]]]}; 'u => {[] _ ms.GetChar[]; RETURN[CONS['z, GetComs[]]]}; 'U => {[] _ ms.GetChar[]; RETURN[CONS['Z, GetComs[]]]}; ' => {[] _ ms.GetChar[]; RETURN[NIL]}; IN ['0..'9] => RETURN[NIL]; ENDCASE => ERROR BtoTError[ms.PeekChar[], " unexpected in trailer ", r]}; GetSpan: PROC RETURNS[n: INT] = {IF ms.EndOf[] THEN RETURN[l]; n _ GetInt[ms]; l _ l-n}; RETURN[P[]]}; ComputeRun: PROC[l: RCList, stop: CHAR] RETURNS [i: INT] = {i _ l.first.span; FOR x: RCList _ l.rest, x.rest UNTIL x=NIL DO FOR t: CList _ x.first.coms, t.rest UNTIL t=NIL DO IF t.first=stop THEN RETURN; ENDLOOP; i _ i+x.first.span; ENDLOOP}; UserExec.RegisterCommand["BravoToTioga", Command, "Conversion program"]; }..