-- SakuraHelperImpl.mesa
-- last edit by Russ Atkinson,  5-Jun-81 15:15:05
-- last edit by Suzuki, 15-Nov-81 19:05:15

DIRECTORY
  IOStream: TYPE USING [CR, FF, TAB, Handle, PutChar], 
  SakuraHelper: TYPE, 
  PPLeaves: TYPE USING [HTIndex, LTIndex], 
  SakuraTree: TYPE USING [Handle, Link, NodeName], 
  SakuraTreeOps: TYPE USING [NSons, NthSon],
  SakuraOps: TYPE USING [GetLog], 
  Rope: TYPE USING [Size, Ref, Text],
  RopeInline: TYPE USING [LowPart];

SakuraHelperImpl: PROGRAM
  IMPORTS IOStream, SakuraOps, SakuraTreeOps, Rope, RopeInline
  EXPORTS SakuraHelper
  = PUBLIC BEGIN OPEN PPLeaves, SakuraTreeOps, Tree: SakuraTree, IOStream, Rope;

  Index: TYPE = LONG INTEGER; 
 
  Char: TYPE = CHARACTER; 
  
  -- this handle is used to hold on to the log stream
  handle: IOStream.Handle ← NIL; 
  indent, position, line, page: Index ← 0; 
  sizing: BOOLEAN ← FALSE;
  lastChar: Char ← 0C; 

  lateTrigger: Index ← 90; 
  earlyTrigger: Index ← 70; 

  Excess: ERROR = CODE; 

  Init: PROC = {
    indent ← position ← line ← page ← 0;
    sizing ← FALSE;
    handle ← SakuraOps.GetLog[];
    };
    
  GetInfo: PROC [t: Tree.Link] RETURNS [info: Index] = {
    DO WITH t SELECT FROM 
         hti: HTIndex => info ← hti.index;
         lti: LTIndex => info ← lti.index;
         x: Tree.Handle =>
	  {info ← x.info; 
                           IF info = 0 THEN 
                              FOR i: NAT IN [1..NSons[t]] WHILE info = 0 DO
                                  info ← GetInfo[NthSon[t, i]]
                                  ENDLOOP}
         ENDCASE => info ← 0; 
       EXIT
       ENDLOOP}; 
  
  GetAttrs: PROC [t: Tree.Link] RETURNS [a1: BOOLEAN, a2: BOOLEAN, a3: BOOLEAN] = {
    WITH t SELECT FROM 
      x: Tree.Handle => RETURN [x.attr[1], x.attr[2], x.attr[3]]
      ENDCASE => a1 ← a2 ← a3 ← FALSE}; 
  
  WriteChar: PROC [c: CHARACTER] = {
    IF (lastChar ← c) < 40C
       THEN 
         {SELECT c FROM 
           TAB => {position ← position + 8; 
                   position ← position - position MOD 8; 
                   lastChar ← ' };
           CR => {position ← 0; line ← line + 1};
           FF => {position ← 0; line ← 0; page ← page + 1};
           ENDCASE}
       ELSE position ← position + 1; 
    IF sizing THEN 
       {IF lastChar # '  AND position >= lateTrigger THEN ERROR Excess; 
        RETURN}; 
    PutChar[handle, c]}; 
  
  WriteId: PROC [r: Ref] = {
    s: Text = NARROW[r];
    len: NAT ← IF s = NIL THEN 0 ELSE RopeInline.LowPart[Size[r]];
    position ← position + len; 
    lastChar ← 'A; 
    IF sizing THEN 
       {IF position > lateTrigger THEN ERROR Excess; 
        RETURN}; 
    FOR i: NAT IN [0..len) DO
        PutChar[handle, s[i]]
        ENDLOOP}; 
  
  WriteText: PROC [r: Ref] = {
    -- we assume that the rope has been flattened
    --    an error occurs if it is not
    IF r # NIL THEN {
       s: Text = NARROW[r];
       FOR i: NAT IN [0..RopeInline.LowPart[Size[s]]) DO
           WriteChar[s[i]]
           ENDLOOP}}; 
  
  WriteQuotedText: PROC [r: Ref] = {
    -- we assume that the rope has been flattened
    --    an error occurs if it is not
    -- we also assume that the scanner has left extra quote marks in
    --    but that the leading and trailing quotes are gone
    WriteChar['"]; 
    IF r # NIL THEN {
       s: Text = NARROW[r];
       FOR i: NAT IN [0..RopeInline.LowPart[Size[s]]) DO
           WriteChar[s[i]]; 
           ENDLOOP}; 
    WriteChar['"]}; 
  
  Indent: PROC = {
    count: Index ← indent - position;
    WHILE (count←count-1) >= 0 DO
          WriteChar[' ]
          ENDLOOP}; 
  
  Break: PROC = {
    IF position > indent THEN WriteChar[CR]; 
    Indent[]}; 
 

  END.