-- PrintBravo.mesa; edited by Johnsson on June 25, 1980  9:22 AM
-- converted to Laurel by Ken Pier,  July 30, 1981  11:21 AM
-- last edited by Ken Pier,  21 Aug. 1981 10:29 am PDT (Friday)
-- converted to Laurel 6.1 by Ken Pier,May 17, 1983  12:05 PM
DIRECTORY
  PrintDefs,
  Press USING [
    Character, GetCurrentPosition, Mica, SetCurrentFont, SetCurrentTabWidth,
    SkipSomeSpace],
  VMDefs: FROM "VMDefs" USING [FileHandle],
  csD: FROM "CoreStreamDefs";

PrintBravo: PROGRAM IMPORTS PrintDefs, Press, csD EXPORTS PrintDefs =
  BEGIN
  
  controlZ: CHARACTER = 32C;
  endOfFile: CHARACTER = LAST[CHARACTER];
  TAB: CHARACTER = 11C;
  return: CHARACTER = 15C;
  backSlash: CHARACTER = '\;
  defaultLM: Press.Mica = 2998;
  
  scanSH: csD.StreamHandle ← NIL;
  copySH: csD.StreamHandle ← NIL;
  bold: BOOLEAN;
  italic: BOOLEAN;
  graphic: BOOLEAN;
  visible: BOOLEAN;
  underline: BOOLEAN;
  leftMargin: INTEGER;
  firstLineLeftMargin: INTEGER;
  rightMargin: INTEGER;
  font: INTEGER;
  setTabs: BOOLEAN;
  tabs: ARRAY [0..15] OF CARDINAL;
  newParagraph: BOOLEAN;
  charactersInParagraph: INTEGER;
  char: CHARACTER;
  
  NotAtEnd: PROCEDURE[s: csD.StreamHandle] RETURNS [BOOLEAN] = 
    BEGIN RETURN[csD.GetLength[s] > csD.GetPosition[s]] END;
    
  Get: PROCEDURE RETURNS [c: CHARACTER] =
    BEGIN
    eos: BOOLEAN ← FALSE;
    c ← csD.Read[scanSH ! csD.EndOfStream => {c ← endOfFile; CONTINUE;};];
    END;
    
  CollectSuffixedInteger: PROCEDURE [c: CHARACTER] RETURNS [INTEGER] =
    BEGIN
    local: INTEGER ← 0;
    IF c IN ['0..'9] THEN -- to avoid harm to char --
      BEGIN
      char ← c;
      WHILE char IN ['0..'9] DO
	local ← local*10 + (char - '0); char ← Get[]; ENDLOOP;
      END;
    RETURN[local];
    END;
    
  IndentStuff: PROCEDURE =
    BEGIN
    k: INTEGER ← IF newParagraph THEN firstLineLeftMargin ELSE leftMargin;
    k ← k - defaultLM;
    IF k < 1 THEN RETURN;
    Press.SkipSomeSpace[k];
    RETURN;
    END;
    
  FontStuff: PROCEDURE =
    BEGIN
    Press.SetCurrentFont[
      font, (IF bold THEN bold ELSE medium),
      (IF italic THEN italic ELSE regular)];
    RETURN;
    END;
    
  SetTab: PROCEDURE =
    BEGIN
    stop, value: CARDINAL;
    char ← Get[];
    IF char IN ['0..'9] THEN stop ← char - '0 ELSE stop ← char - 'a;
    char ← Get[];
    IF char = ', THEN
      BEGIN
      value ← MAX[0, CollectSuffixedInteger[Get[]]];
      tabs[stop] ← value;
      setTabs ← TRUE;
      END
    ELSE -- uniform tabs
      BEGIN
      value ← stop;
      WHILE char IN ['0..'9] DO
	value ← value*10 + (char - '0); char ← Get[]; ENDLOOP;
      Press.SetCurrentTabWidth[value];
      setTabs ← FALSE;
      END;
    UNTIL char = ') DO char ← Get[] ENDLOOP;
    char ← Get[];
    RETURN;
    END;
    
  AdvanceToTab: PROCEDURE =
    BEGIN
    x: Press.Mica ← Press.GetCurrentPosition[].x + defaultLM;
    FOR stop: CARDINAL IN [0..15] DO
      IF tabs[stop] # LAST[CARDINAL] AND tabs[stop] > CARDINAL[x] THEN
	{Press.SkipSomeSpace[tabs[stop] - x]; EXIT};
      REPEAT FINISHED => Press.Character[TAB];
      ENDLOOP;
    RETURN;
    END;
    
  BravoIt: PUBLIC PROCEDURE [fh: VMDefs.FileHandle] =
    BEGIN
    j: INTEGER;
    tempPos: csD.Position;
    c: CHARACTER;
    setTabs ← FALSE;
    tabs ← ALL[LAST[CARDINAL]];
    scanSH ← csD.Open[fh, byte, read];
    copySH ← csD.Open[fh, byte, read];
    BEGIN ENABLE UNWIND => BEGIN scanSH ← PrintDefs.DestroyS[scanSH];
                                 copySH ← PrintDefs.DestroyS[copySH]; END;
    IF ~NotAtEnd[scanSH] THEN RETURN;
    charactersInParagraph ← 0;
    char ← Get[]; -- need a running start --
      WHILE NotAtEnd[scanSH] DO
      newParagraph ← TRUE;
      Press.Character[return]; -- return before every para, even first --
      italic ← bold ← graphic ← visible ← underline ← FALSE;
      leftMargin ← firstLineLeftMargin ← defaultLM;
      font ← 0;
      tempPos ← csD.GetPosition[scanSH] - 1;
      csD.SetPosition[copySH, tempPos]; -- for the later copy --
      UNTIL char = controlZ OR char = endOfFile DO
	charactersInParagraph ← charactersInParagraph + 1; char ← Get[]; ENDLOOP;
      WHILE char # backSlash AND char # return AND char # endOfFile DO
	SELECT char FROM
	  'l => leftMargin ← CollectSuffixedInteger['0];
	  'd => firstLineLeftMargin ← CollectSuffixedInteger['0];
	  'r => rightMargin ← CollectSuffixedInteger['0];
	  '( => SetTab[];
	  ENDCASE => char ← Get[];
	ENDLOOP;
      IF char = backSlash THEN
	BEGIN
	WHILE char # return AND char # endOfFile DO
	  SELECT char FROM
	    'b => BEGIN bold ← TRUE; char ← Get[]; END;
	    'B => BEGIN bold ← FALSE; char ← Get[]; END;
	    'i => BEGIN italic ← TRUE; char ← Get[]; END;
	    'I => BEGIN italic ← FALSE; char ← Get[]; END;
	    'g => BEGIN graphic ← TRUE; char ← Get[]; END;
	    'G => BEGIN graphic ← FALSE; char ← Get[]; END;
	    'v => BEGIN visible ← TRUE; char ← Get[]; END;
	    'V => BEGIN visible ← FALSE; char ← Get[]; END;
	    'u => BEGIN underline ← TRUE; char ← Get[]; END;
	    'U => BEGIN underline ← FALSE; char ← Get[]; END;
	    'f => font ← CollectSuffixedInteger['0];
	    'o => -- skip for now --[] ← CollectSuffixedInteger['0];
	    '0, '1, '2, '3, '4, '5, '6, '7, '8, '9 =>
	      BEGIN
	      j ← CollectSuffixedInteger[char];
	      -- have new run ... first set in ↑ stuff: --
	      IF newParagraph THEN IndentStuff[];
	      newParagraph ← FALSE;
	      FontStuff[];
	      THROUGH [0..j) DO
		IF charactersInParagraph > 0 THEN
		  BEGIN
		  c ← csD.Read[copySH];
		  IF c = TAB AND setTabs THEN AdvanceToTab[]
		  ELSE Press.Character[c];
		  IF c = return THEN IndentStuff[];
		  charactersInParagraph ← charactersInParagraph - 1;
		  END;
		ENDLOOP;
	      END;
	    ENDCASE => char ← Get[];
	  ENDLOOP;
	END;
      IF char = return THEN char ← Get[];
      IF charactersInParagraph > 0 THEN
	BEGIN
	IF newParagraph THEN IndentStuff[];
	newParagraph ← FALSE;
	FontStuff[];
	WHILE charactersInParagraph > 0 DO
	  c ← csD.Read[copySH];
	  IF c = TAB AND setTabs THEN AdvanceToTab[] ELSE Press.Character[c];
	  IF c = return THEN IndentStuff[];
	  charactersInParagraph ← charactersInParagraph - 1;
	  ENDLOOP;
	END;
  ENDLOOP;
    scanSH ← PrintDefs.DestroyS[scanSH];
    copySH ← PrintDefs.DestroyS[copySH]; 
    END;--of ENABLED UNWIND block
    END;--of PROC BravoIt
    
  
  END...