EXTERNAL KFORMAT::DOTEXT;

{+++++++++++++++++++++++++++++++++++++++++++++++++++}
{+ DOTEXT MODULE FOR KFORMAT Text Output Processor +}
{+++++++++++++++++++++++++++++++++++++++++++++++++++}

{ compiler options for Pascal/Z compiler. }
{$C-}{ control-c checking OFF }
{$M-}{ integer mult & divd error checking OFF }
{$F-}{ floating point error checking OFF }

{
	process text
}
PROCEDURE DOTEXT(inbuf:BUFFER);
VAR	i	:int;
	wordbuf :BUFFER;

  {
	delete leading blanks & set tival
  }
  PROCEDURE LEADBL(VAR lbbuf:BUFFER);
  VAR	i :int;
  BEGIN
    DOBREAK;
    i := 1;
    WHILE ((lbbuf[i]=SPACE) and (i < LENGTH(lbbuf))) DO i := i + 1;
    IF (lbbuf[i] <> NEWLINE) THEN tival := tival + i - 1;
    IF ( i<>1 ) THEN DELETE(lbbuf,1,i-1);	{ *** 3-81 *** }
  END;


  {
	width of a printed line
  }
  FUNCTION WIDTH(VAR w:BUFFER):int;
  VAR	i,wdth :int;
  BEGIN
    wdth := 0;
    FOR i := 1 TO LENGTH(w) DO
      IF (w[i]=BACKSPACE) THEN
	wdth := wdth - 1
      ELSE IF (w[i] <> NEWLINE) THEN
	wdth := wdth + 1;
    WIDTH := wdth;
  END;

  {
	centers by setting temporary indent
  }
  PROCEDURE CENTER(VAR cebuf:BUFFER);
  var	k: int;
  BEGIN
    k := ( rmval + tival - WIDTH(cebuf) ) DIV 2;
    tival := IMAX( k,0 );
  END;

  {
	replace non-white space chars with bksp, "_"
  }
  PROCEDURE UNDERLINE(VAR inbuf:BUFFER);
  VAR	u :int;
	ulstr :DSTRING;
  BEGIN
    ulstr := '  ';
    ulstr[1] := BACKSPACE;
    ulstr[2] := '_';
    u := 1;
    WHILE (u <= LENGTH(inbuf)) DO
      begin
      IF ( (inbuf[u] <> SPACE)
       AND (inbuf[u] <> TAB)
       AND (inbuf[u] <> BACKSPACE)
       AND (inbuf[u] <> NEWLINE) ) THEN
	BEGIN  INSERT(ulstr,inbuf,u+1);
	       u := u + 3
	END
      ELSE
	u := u + 1;
      end;
  END;

  {
	spread words to justify right margin
  }
  PROCEDURE SPREAD(VAR outbuf:BUFFER; outp, nextra, outwds:int);
  VAR	nb,	{ number blanks }
	ne,	{ number extra	}
	nholes, { number holes	}
	i, j: int;
  BEGIN
    IF (nextra > 0) THEN
      BEGIN{nextra > 0}
	IF (outwds > 0) and ( spacefill ) THEN
	  BEGIN
	    direction := NOT direction; 	{ tobble bias direction }
	    ne := nextra;
	    nholes := outwds - 1;
	    i := LENGTH(outbuf) - 1;		 { point at final non-blank }
	    WHILE ( ne > 0 ) DO
	      BEGIN
		WHILE ( outbuf[i] <> SPACE ) DO i := i - 1;
		IF ( direction ) THEN
		  nb := (ne-1) DIV nholes + 1	{ rounded }
		ELSE
		  nb := ne DIV nholes;		{ truncated }
		ne := ne - nb;
		nholes := nholes - 1;
		WHILE ( nb > 0 ) DO		{ insert extra blanks }
		  BEGIN
		    INSERT(' ',outbuf,i+1);
		    nb := nb - 1;
		  END;
		i := i - 1
	      END {while ne > 0}
	  END
      END {IF nextra > 0}
  END;

  {
	put a word in outbuf including margin justification
  }
  PROCEDURE PUTWORD(VAR pwbuf:BUFFER);
  VAR	w, last,
	llval, nextra: int;
  BEGIN
    w := WIDTH(pwbuf); { printable width of pwbuf }
    last := LENGTH(pwbuf) + outp + 1;	{ new end of outbuf }
    llval := rmval - tival;  { printable line length }
    IF ((outp > 0)
      AND ( ((outw + w) > llval) OR (last > MAXBUF) ) ) THEN{ too big }
	BEGIN
	  last := last - outp; { remember end of wrdbuf }
	  nextra := llval - outw + 1; { # blanks needed to pad }
	  IF ( spacefill ) THEN
	    SPREAD(outbuf,outp,nextra,outwds);
	  IF ((nextra > 0) AND (outwds > 1)) THEN
	    outp := outp + nextra;
	  DOBREAK { flush previous line }
	END;
    outp := last;
    { *  outbuf := CONCAT(outbuf,pwbuf,space);	* }
    append(outbuf,pwbuf);		{ add new word to outbuf }
    append(outbuf,space);		{ add a blank		 }
    outw := outw + w + 1;		{ update output width	 }
    outwds := outwds + 1;		{ increment the word count }
  END;


  {
	get a non-blank word from inbuf[] to wdbuf[] and
	advance g.  Returns length of wdbuf.
  }
  FUNCTION GETWORD(VAR inbuf: BUFFER; VAR g: int; VAR wdbuf: BUFFER):int;
  VAR	st: int;
  BEGIN
    WHILE (((inbuf[g]=SPACE) OR (inbuf[g]=TAB))
	  AND (g < LENGTH(inbuf))) DO g := g + 1;
    st := g;
    SKIPCHARS(inbuf,g);
    wdbuf := COPY(inbuf,st,g-st);
    GETWORD := LENGTH(wdbuf);
  END;

BEGIN {dotext}
  IF ((inbuf[1]=SPACE) OR (inbuf[1]=NEWLINE)) THEN
    LEADBL(inbuf);			{ * move left, set tival * }
  IF ( ulval > 0 ) THEN 		{ * underlining * }
    BEGIN
      UNDERLINE(inbuf);
      ulval := ulval - 1
    END;
  IF ( ceval > 0 ) THEN 		{ * centering in effect * }
    BEGIN
      CENTER(inbuf);
      PUTTEXT(inbuf);
      ceval := ceval - 1;
    END
  ELSE IF (inbuf[1]=NEWLINE) THEN	{ * all blank line * }
    PUTTEXT(inbuf)
  ELSE IF ( NOT fill ) THEN		{ * un-filled text passes * }
    PUTTEXT(inbuf)			{ * text "as is"	  * }
  ELSE					{ * filled text * }
    BEGIN
      i := 1;
      WHILE ( GETWORD(inbuf,i,wordbuf) > 0 ) DO
	PUTWORD(wordbuf);
    END;
END;  {dotext}

{END EXTERNAL}.

