{$D+,S+,L+,R-,I+}

UNIT TWU1RPT;

(*****************)
(**) INTERFACE (**)
(*****************)

USES Dos;
CONST
	Ctl_CRLF = ^M^J;	{ "new-line" sequence for MS/PC Dos }
	Ctl_FF   = ^L;		{ "new-page" sequence for MS/PC Dos }

TYPE  FileFlags = (FileActive,FileQuiet,FileFailure);

VAR	LinesRemaining,		{ on current page }
	ColumnsRemaining,	{ on current line }
	ColumnsUsed		{ on current line }
			: LongInt;
	FileStatus 	: FileFlags;

PROCEDURE PutTxt(S : String);
PROCEDURE PutCtl(S : String);
PROCEDURE SetCol(I : Integer);
PROCEDURE NewTxtLine;
PROCEDURE NewTxtPage;
PROCEDURE OpenTxt(S : String; LineMax, ColumnMax : Integer);
PROCEDURE CloseTxt;

(**********************)
(**) IMPLEMENTATION (**)
(**********************)

CONST
	Ctl_EOF  = ^Z;	{ "end-file" sequence for MS/PC Dos }
	Ctl_CR   = ^M;	{ "Carriage-Return"                 }
	Ctl_LF   = ^J;	{ "Line-Feed"                       }

VAR	MaxLinesOnPage,
	MaxColsPerLine,
	CurrentLine,
	CurrentColumn : LongInt;

	NoLineWrap, NoPageBreak : Boolean;

	FileState : FileFlags;
	TextFile  : Text;
        Spaces    : String;

PROCEDURE FeedBack;
BEGIN
	IF NOT (FileState = FileActive) THEN
	BEGIN
		LinesRemaining   := 0;
		ColumnsRemaining := 0;
		ColumnsUsed      := 0;
	END ELSE
	BEGIN
		LinesRemaining   := MaxLinesOnPage + 1 - CurrentLine;
		ColumnsRemaining := MaxColsPerLine + 1 - CurrentColumn;
		ColumnsUsed      := CurrentColumn  - 1;
	END;
	FileStatus := FileState;
END;	{FeedBack}

PROCEDURE PutCR;
BEGIN
	PutCtl(Ctl_CR);
	CurrentColumn := 1;
END;

PROCEDURE PutLF;
BEGIN
	IF NoPageBreak
	THEN PutCtl(Ctl_LF)
	ELSE
		IF CurrentLine = MaxLinesOnPage THEN
		BEGIN
			PutCtl(Ctl_FF);
			CurrentLine := 0
		END
		ELSE    PutCtl(Ctl_LF);

	Inc(CurrentLine);
END;

PROCEDURE PutCRLF;
BEGIN	PutCR;	PutLF;	END;

PROCEDURE PutFF;
BEGIN	PutCtl(Ctl_FF);	CurrentLine := 1;	END;

PROCEDURE PutEOF;
BEGIN	PutCtl(Ctl_EOF);	END;

FUNCTION ScanCtls(S : String):Integer;
LABEL Found;
VAR J : Integer; I, L : Byte;
BEGIN
	J := 0; L := Length(S);
	FOR I := 1 TO L DO
		IF S[I] in [Ctl_EOF,Ctl_FF,Ctl_LF,Ctl_CR]
		THEN BEGIN
			J := I; GOTO Found
		END;
Found:
	ScanCtls := J
END;

PROCEDURE PutTxt(S : String);
VAR CtlPos, Slice : Integer;
BEGIN
	CtlPos := ScanCtls(S);
	WHILE Length(S) > 0 DO BEGIN
		IF CurrentColumn > MaxColsPerLine THEN PutCRLF;
		IF CurrentLine   > MaxLinesOnPage THEN PutFF;
		Slice := Length(S);
		IF CtlPos = 0
		THEN CtlPos := Slice + 1
		ELSE
			IF Slice > CtlPos
			THEN Slice := CtlPos - 1;
		IF Slice > MaxColsPerLine THEN Slice := MaxColsPerLine;
		IF Slice > 0 THEN
		BEGIN
			PutCtl(Copy(S,1,Slice));
			Delete(S,1,Slice);
			CtlPos := CtlPos - Slice;
			CurrentColumn := CurrentColumn + Slice
		END ELSE
		BEGIN
			IF S[1] = Ctl_EOF THEN PutEOF ELSE
			IF S[1] = Ctl_FF  THEN PutFF  ELSE
			IF S[1] = Ctl_LF  THEN PutLF  ELSE
			IF S[1] = Ctl_CR  THEN PutCR;
			Delete(S,1,1);
			IF Length(S) > 0 THEN CtlPos := ScanCtls(S);
		END;
	END; {WHILE}
	FeedBack;
END;

PROCEDURE PutCtl(S : String);
BEGIN
	IF FileState = FileActive THEN
	BEGIN
		{$I-} Write(TextFile,S); {$I+}
		IF IOResult <> 0 THEN CloseTxt
	END;
END;

PROCEDURE NewTxtLine;
BEGIN
	PutCRLF;
	FeedBack;
END;

PROCEDURE NewTxtPage;
BEGIN
	IF CurrentColumn > 1 THEN PutCRLF;
	IF CurrentLine > 1 THEN PutFF;
	FeedBack;
END;

PROCEDURE OpenTxt(S : String; LineMax, ColumnMax : Integer);
BEGIN
	IF FileState = FileActive THEN CloseTxt;

	Assign(TextFile,S);
	NoPageBreak := (LineMax < 1) OR (LineMax > 255);
	IF NoPageBreak
		THEN MaxLinesOnPage := MaxLongInt
		ELSE MaxLinesOnPage := LineMax;
	NoLineWrap  := (ColumnMax < 1) OR (ColumnMax > 255);
	IF NoLineWrap
		THEN MaxColsPerLine := MaxLongInt
		ELSE MaxColsPerLine := ColumnMax;
	CurrentLine    := 1;
	CurrentColumn  := 1;
	FileState      := FileActive;

	{$I-} ReWrite(TextFile); {$I+}

	IF IOResult <> 0 THEN FileState := FileFailure;
	IF FileState = FileFailure
	THEN CloseTxt
	ELSE FeedBack;
END;

PROCEDURE SetCol(I : Integer);
Var J : Integer;
BEGIN
	IF FileState = FileActive THEN
	IF MaxColsPerLine > I   THEN
	BEGIN
		IF CurrentColumn  > I THEN PutCRLF;
                J := I - CurrentColumn;
                IF J < SizeOf(Spaces) THEN
                BEGIN
                   Spaces[0] := Chr(J);
                   PutTxt(Spaces);
                END ELSE
		WHILE CurrentColumn < I DO PutTxt(' ')
	END;
	FeedBack;
END;

PROCEDURE CloseTxt;
BEGIN
	IF FileState = FileActive THEN
	BEGIN
	{	PutEOF; }
		{$I-} Close(TextFile); {$I+}
		MaxLinesOnPage := 0;
		MaxColsPerLine := 0;
		CurrentLine    := 0;
		CurrentColumn  := 0;
		FileState      := FileQuiet;
		NoLineWrap     := True;
		NoPageBreak    := True;
		FeedBack;
	END;
END;

BEGIN	{ UNIT INITIALIZATION CODE }

        FillChar(Spaces,SizeOf(Spaces),' ');
	MaxLinesOnPage := 0;
	MaxColsPerLine := 0;
	CurrentLine    := 0;
	CurrentColumn  := 0;
	FileState      := FileQuiet;
	FeedBack;
END.