DIRECTORY Ascii USING [Control, Digit, Upper], BtoT, Commander USING [CommandProc, Register], CommandTool USING [Failed, ParseToList, ResolveRelativePath], RefText USING [AppendChar, ObtainScratch, ReleaseScratch], Rope USING [Concat, Equal, Fetch, FromRefText, IsEmpty, Length, ROPE, Substr], FS USING [Error, StreamOpen], IO, TiogaFileOps; BravoToTioga: CEDAR PROGRAM IMPORTS Ascii, Commander, CommandTool, RefText, Rope, FS, IO, TiogaFileOps EXPORTS BtoT = BEGIN ROPE: TYPE = Rope.ROPE; RCList: TYPE = LIST OF RECORD[coms: CList, span: INT]; CList: TYPE = LIST OF CHAR; BtoTError: ERROR[c: CHAR, s1, s2: ROPE] = CODE; TokenProc: IO.BreakProc = TRUSTED { RETURN[SELECT char FROM IO.SP, IO.TAB, IO.CR, ', => sepr, '_ => break, ENDCASE => other]; }; Command: Commander.CommandProc = { fileNames: LIST OF ROPE; actualOutputName: ROPE; errors: ROPE; args: LIST OF ROPE; nArgs: NAT; outputName: ROPE _ NIL; IsArrow: PROC [r: ROPE] RETURNS [BOOL] = { RETURN[Rope.Equal[r, "_"]]; }; [list: args, length: nArgs] _ CommandTool.ParseToList[cmd ! CommandTool.Failed => {msg _ errorMsg; CONTINUE; }]; IF NOT msg.IsEmpty[] THEN RETURN[$Failure, msg]; FOR l: LIST OF Rope.ROPE _ args, l.rest WHILE l # NIL DO l.first _ CommandTool.ResolveRelativePath[l.first]; ENDLOOP; SELECT nArgs FROM 0 => GOTO SyntaxError; 1 => { IF IsArrow[args.first] THEN GOTO SyntaxError; outputName _ NIL; fileNames _ args; }; 2 => { IF IsArrow[args.rest.first] THEN GOTO SyntaxError; IF IsArrow[args.first] THEN { outputName _ NIL; fileNames _ args.rest; } ELSE { outputName _ NIL; fileNames _ args; }; }; ENDCASE => { IF IsArrow[args.rest.first] THEN { outputName _ args.first; fileNames _ args.rest.rest; } ELSE { outputName _ NIL; fileNames _ args; }; }; [actualOutputName: actualOutputName, errors: errors] _ BravoToTioga[fileNames: fileNames, outputName: outputName]; IF errors.Length[] > 0 THEN { result _ $Failure; msg _ errors; } ELSE msg _ Rope.Concat[actualOutputName, " written.\n"]; EXITS SyntaxError => { result _ $Failure; msg _ "Correct syntax: BravoToTioga { outputFile _ } input1 input2 ...\n"; }; }; CharProc: TYPE = PROC [char: CHAR] RETURNS [keep: BOOL]; GetSequence: PROC [str: IO.STREAM, cp: CharProc] RETURNS [r: ROPE] = { buf: REF TEXT _ RefText.ObtainScratch[100]; c: CHAR; DO c _ str.GetChar[]; IF cp[c] THEN buf _ RefText.AppendChar[buf, c] ELSE { str.Backup[c]; EXIT; }; ENDLOOP; r _ Rope.FromRefText[buf]; RefText.ReleaseScratch[buf]; }; DotPos: PROC [r: Rope.ROPE] RETURNS [INT] = { len: INT _ r.Length[]; FOR pos: INT DECREASING IN [0..len) DO SELECT r.Fetch[pos] FROM '. => RETURN[pos]; '/, '>, '] => RETURN[len]; ENDCASE; ENDLOOP; RETURN[len]; }; NextParagraph: PROC [str: IO.STREAM] RETURNS [content: ROPE, paragraphData: ROPE, runCoding: ROPE] = { ToControlZ: CharProc = {RETURN[char#Ascii.Control['Z]]}; ToBackslash: CharProc = {RETURN[char#'\\ AND char#IO.CR]}; ToCR: CharProc = {RETURN[char#IO.CR]}; content _ GetSequence[str, ToControlZ]; [] _ str.GetChar[]; -- throw away ^Z paragraphData _ GetSequence[str, ToBackslash]; IF str.PeekChar[]='\\ THEN { [] _ str.GetChar[]; runCoding _ GetSequence[str, ToCR]} ELSE runCoding_""; IF str.PeekChar[ ! IO.EndOfStream => CONTINUE] = IO.CR THEN [] _ str.GetChar[]; }; 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; }; Attr: PROC[s: ROPE, a: CHAR, dflt: INT _ 0] RETURNS [present: BOOLEAN _ FALSE, val: INT] = { i, j, k: INT; digit: CHAR; sl: INT = s.Length[]; val _ dflt; FOR i IN [0..sl) DO IF s.Fetch[i]=a THEN { value: INT _ 0; FOR k IN (i .. sl) UNTIL Ascii.Digit[(digit _ s.Fetch[k])] DO NULL ENDLOOP; present _ TRUE; FOR j IN [k .. sl) WHILE Ascii.Digit[(digit _ s.Fetch[j])] DO val _ value _ value * 10 + (digit - '0); ENDLOOP }; ENDLOOP; }; SectionNum: PROC[s: ROPE] RETURNS [present: BOOLEAN _ FALSE] = { sl: INT = s.Length[]; i, nj: INT; IF s.IsEmpty[] THEN RETURN[FALSE]; i _ 0; DO FOR nj IN [i .. sl) WHILE s.Fetch[nj] IN ['0..'9] DO NULL ENDLOOP; IF s.Fetch[nj]='. THEN {i _ nj+1; LOOP} ELSE RETURN [i#0]; ENDLOOP}; PSx: TYPE = [0..20); FmtType: TYPE = {root, block, center, contents, continuation, display, example, head, head1, head2, head3, head4, head5, indent, item, lead1, lead2, lead3, logo, memoHead, note, pageBreak, quote, reference, table, table1, table2, table3, title, subtitle}; FmtRopes: ARRAY FmtType OF ROPE = ["root", "block", "center", "contents", "continuation", "display", "example", "head", "head1", "head2", "head3", "head4", "head5", "indent", "item", "lead1", "lead2", "lead3", "logo", "memoHead", "note", "pageBreak", "quote", "reference", "table", "table1", "table2", "table3", "title", "subtitle"]; BravoToTioga: PUBLIC PROC[fileNames: LIST OF ROPE, outputName: ROPE _ NIL] RETURNS[actualOutputName: ROPE _ NIL, errors: ROPE _ NIL] = { st: IO.STREAM; ParentStack: ARRAY PSx OF RECORD[node: TiogaFileOps.Ref, indent: INT, format: FmtType]; psp: PSx; node: TiogaFileOps.Ref; format: FmtType; root: TiogaFileOps.Ref; fileName, rootName: ROPE; dotPos: INT; indent: INT; FOR fl: LIST OF ROPE _ fileNames, fl.rest UNTIL fl = NIL DO fileName _ fl.first; dotPos _ DotPos[fileName]; IF Rope.Equal[Rope.Substr[fileName, dotPos], ".tioga", FALSE] THEN { errors _ Rope.Concat[fileName, " is already a tioga file\n"]; RETURN[NIL, errors]; }; IF dotPos = fileName.Length[] THEN { rootName _ fileName; fileName _ fileName.Concat[".bravo"]; } ELSE rootName _ fileName.Substr[0, dotPos]; IF fl = fileNames THEN { -- determine the output file name the first time and create Tioga root actualOutputName _ IF outputName.IsEmpty[] THEN rootName.Concat[".tioga"] ELSE outputName; root _ TiogaFileOps.CreateRoot[]; TiogaFileOps.SetStyle[root, "Cedar"]; node _ root; ParentStack[0] _ [node: root, indent: 0, format: root] }; st _ NIL; st _ FS.StreamOpen[fileName, $read ! FS.Error => { IF error.group = $user THEN { errors _ error.explanation; CONTINUE; }; }]; IF NOT errors.IsEmpty[] OR st = NIL THEN RETURN[NIL, errors]; psp _ 0; UNTIL st.EndOf[] DO c, p, r: ROPE; [content: c, paragraphData: p, runCoding: r] _ NextParagraph[st]; indent _ Attr[p, 'l, 3000].val; UNTIL psp<=1 OR indent >= ParentStack[psp].indent DO psp _ psp-1 ENDLOOP; SELECT TRUE FROM -- decide on a format NOT c.IsEmpty[] AND c.Fetch[0] = '( AND ParentStack[psp].format=block OR ParentStack[psp].format=item => format _ item; Attr[p, 'e].val>=18 AND Attr[p, 'c].present AND Attr[p, 'k].val>=360 => format _ title; Attr[p, 'k].val>=36 AND SectionNum[c] => format _ head; Attr[p, 'c].present => format _ center; ENDCASE => format _ block; SELECT TRUE FROM format=head AND ParentStack[psp].format#head => psp _ MAX[1, psp-1]; indent>ParentStack[psp].indent OR ParentStack[psp].format=title OR ParentStack[psp].format=head OR (ParentStack[psp].format#item AND format=item) => psp _ MIN[LAST[PSx], psp+1]; ENDCASE; ParentStack[psp] _ [node: (node _ TiogaFileOps.InsertAsLastChild[ParentStack[psp-1].node]), indent: indent, format: format]; TiogaFileOps.SetContents[node, c]; TiogaFileOps.SetFormat[node, FmtRopes[format]]; {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; x: INT; c _ c.rest; IF d='2 THEN { TiogaFileOps.SetFormat[node, FmtRopes[format_logo]]; ParentStack[psp].format _ format} ELSE { x _ ComputeRun[l, 'f]; SELECT d FROM '0 => NULL; '1 => TiogaFileOps.AddLooks[node, here, x, 's, root]; '2 => NULL; '3 => TiogaFileOps.AddLooks[node, here, x, 'm, root]; '4 => TiogaFileOps.AddLooks[node, here, x, 'g, root]; '5 => TiogaFileOps.AddLooks[node, here, x, 'l, root]; '6 => TiogaFileOps.AddLooks[node, here, x, 'o, root]; '7 => {TiogaFileOps.AddLooks[node, here, x, 'o, root]; TiogaFileOps.AddLooks[node, here, x, 's, root]}; '8 => TiogaFileOps.AddLooks[node, here, x, 'f, root]; '9 => {TiogaFileOps.AddLooks[node, here, x, 'o, root]; TiogaFileOps.AddLooks[node, here, x, 'x, root]; TiogaFileOps.AddLooks[node, here, x, 'l, root]}; ENDCASE}}; 't, 'o => c _ c.rest; 'b, 'i, 'z => {TiogaFileOps.AddLooks[node, here, ComputeRun[l, Ascii.Upper[c.first]], c.first, root]}; 'u, 'd => {TiogaFileOps.AddLooks[node, here, ComputeRun[l, 'D], c.first, root]}; ENDCASE; c _ c.rest; ENDLOOP; here _ here + l.first.span; ENDLOOP}; ENDLOOP; st.Close[]; ENDLOOP; TiogaFileOps.Store[root, actualOutputName]; }; ParseRC: PROC[r: ROPE, l: INT] RETURNS[RCList] = { ms: IO.STREAM _ IO.RIS[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}; Commander.Register["BravoToTioga", Command, "Conversion program: BravoToTioga [output] _ input1 input2 ... "]; END. December 29, 1983 11:40 am, Stewart, Cedar 5 December 31, 1983 9:22 am, MBrown, rope = NIL bugs December 31, 1983 9:35 am, MBrown, CommandTool.ResolveRelativePath[args.first] -> CommandTool.ResolveRelativePath[l.first] ¾BravoToTioga.mesa, Jim Morris, July 12, 1982 3:35 pm last written by Bill Paxton, November 30, 1982 9:20 am Last Edited by: Plass, March 16, 1983 11:18 am Last Edited by: Mitchell, June 3, 1983 6:06 pm Last Edited by: Stewart, December 29, 1983 11:40 am Last Edited by: MBrown, December 31, 1983 9:35 am Returns position of the . denoting the extension CharProc: TYPE = PROC [char: CHAR] RETURNS [quit: BOOL _ FALSE, include: BOOL _ TRUE] Ê Ÿ˜Jšœ4™4Jšœ6™6J™.J™.J™3J™2šÏk ˜ Jšœœ˜$J˜Jšœ œ˜(Jšœ œ,˜=Jšœœ-˜:Jšœœ6œ ˜NJšœœ˜Jšœ˜J˜ J˜—Jšœœ˜Jšœ/œœ˜JJšœ˜Jš˜Jšœœœ˜J˜Jš œœœœœœ˜6Jš œœœœœ˜J˜Jš œ œœ œœ˜/J˜šœ œ œ˜#šœœ˜Jš œœœœœœ˜"Jšœ ˜ Jšœ ˜—Jšœ˜—J˜šœ"˜"Jšœ œœœ˜Jšœœ˜Jšœœ˜ Jšœœœœ˜Jšœœ˜ Jšœ œœ˜Jš Ïnœœœœœœ˜IJšœcœ˜pJšœœœœ˜0š œœœœœœ˜8J˜3Jšœ˜—šœ˜Jšœœ ˜˜Jšœœœ ˜-Jšœ œ˜Jšœ˜J˜—˜Jšœœœ ˜2šœœ˜Jšœ œ˜Jšœ˜J˜—šœ˜Jšœ œ˜Jšœ˜J˜—J˜—šœ˜ šœœ˜"Jšœ˜Jšœ˜J˜—šœ˜Jšœ œ˜Jšœ˜J˜—J˜——Jšœr˜ršœœ˜J˜J˜ J˜—Jšœ4˜8Jš˜šœ˜Jšœ˜JšœJ˜JJšœ˜—Jšœ˜—J˜Jš žœœœœœœ˜8J˜š ž œœœœœœ˜FJšœœœ˜+Jšœœ˜š˜J˜Jšœœ!˜.šœ˜Jšœ˜Jšœ˜J˜—Jšœ˜—Jšœ˜Jšœ˜J˜—J˜J™0š žœœ œœœ˜-Jšœœ˜š œœ œœ ˜&šœ˜Jšœœ˜Jšœœ˜Jšœ˜—Jšœ˜—Jšœ˜ J˜—J˜šž œœœœ˜$Jšœ œœ œ˜AJšœU™UJšœœ˜8Jš œœ œœœ˜:Jšœœœœ˜'J˜Jšœ'˜'JšœÏc˜$Jšœ.˜.šœœ˜Jšœ7˜7—Jšœ˜Jš œœœœœœ˜OJšœ˜—unitš žœœ œœœ œ ˜<š œœœœ ˜=Jšœ-˜-Jšœ˜—Jšœ˜—šžœœœœœœ œœœ˜]Jšœ œ˜ Jšœœ˜ Jšœœ˜Jšœ ˜ šœœ ˜šœœ˜Jšœœ˜Jš œœ œ#œœœ˜KJšœ œ˜šœœ œ#œ˜>Jšœ(˜(Jšœ˜ —Jšœ˜——Jšœ˜—š ž œœœœ œœ˜@Jšœœ˜Jšœœ˜ Jšœ œœœ˜"J˜š˜Jšœœ œ œ œœœ˜BJš œœ œœœ˜:Jšœ˜ ——Kšœœ ˜Kšœ œò˜ÿKšœ œ œœ®˜Íšž œœœ œœœœœ˜JJš œœœ œœ˜=Jšœœœ˜Jš œ œœœ!œ˜WJšœ ˜ Jšœ˜J˜Jšœ˜Jšœœ˜Jšœœ˜ Jšœœ˜ š œœœœœœ˜;Jšœ˜Jšœ˜šœ5œœ˜DJšœ=˜=Jšœœ ˜J˜—šœœ˜$Jšœ˜Jšœ%˜%Jšœ˜—Jšœ'˜+šœœŸF˜_Jšœœœœ ˜ZJšœ!˜!Jšœ%˜%J˜ J˜9—Jšœœ˜ šœœœ ˜2šœœ˜Jšœ˜Jšœ˜ Jšœ˜—Jšœ˜—Jšœœœœœœœ ˜=J˜šœ ˜Jšœ œ˜JšœA˜AJšœ˜Jšœœ#œ œ˜IšœœœŸ˜&Jšœ œœœ/˜wšœœœ˜GJšœ˜—Jšœœ ˜7Jšœ'˜'Jšœ˜—šœœ˜Jšœ œ'œ ˜DJš œœœœœœœ˜±Jšœ˜—Jšœ‚˜‚Jšœ"˜"Jšœ/˜/Jšœœ˜šœ,œœ˜=J˜šœœ˜šœ ˜šœ œ˜Jšœœ˜J˜ šœœ˜Jšœ4˜4Jšœ!˜!—šœ˜Jšœ˜Jšœ˜ Jšœœ˜ Jšœ6˜6Jšœœ˜ Jšœ6˜6Jšœ6˜6Jšœ5˜5Jšœ6˜6šœ6˜6Jšœ0˜0—Jšœ6˜6šœ6˜6Jšœ/˜/Jšœ0˜0—Jšœ˜ ——J˜Jšœf˜fJšœQ˜QJšœ˜J˜ Jšœ˜—J˜Jšœ˜ —Jšœ˜—J˜ Jšœ˜—Jšœ+˜+Jšœ˜—š žœœœœœ ˜2Jš œœœœœ˜šœœœ ˜Jšœ œœœ˜ ˜Jšœœ ˜Jšœœ œ˜——šžœœœ ˜!Jšœ œœœ˜šœ˜˜˜JšœœŸ/˜EJšœœœœœœœœ˜KJšœ˜——Jšœ œœœ˜Ešœ*˜*Jšœœ˜&—Jšœœœ˜8Jšœœœ˜8Jšœœœ˜'Jšœ œœ˜Jšœœ9˜I——šžœœœœ˜!Jšœ œœ˜Jšœ˜J˜ —šœœ˜ J˜——š ž œœœœœ˜:˜šœœœ˜-šœ!œœ˜2Jšœœœ˜Jšœ˜—J˜Jšœ˜ J˜————J˜nJ˜Jšœ˜J˜,Jšœ*œ˜2Jšœz˜z—…—'6e