-- TexIO.mesa

-- last written by Doug Wyatt, January 3, 1980  1:56 PM

DIRECTORY
	TexDefs: FROM "TexDefs",
	TexMathDefs: FROM "TexMathDefs",
	TexIODefs: FROM "TexIODefs",
	TexStringDefs: FROM "TexStringDefs"
		USING[AppendChar,AppendNumber],
	DisplayDefs: FROM "DisplayDefs"
		USING[SetFont],
	FontDefs: FROM "FontDefs"
		USING[FontHandle,CreateFont],
	ImageDefs: FROM "ImageDefs"
		USING[CleanupItem,CleanupMask,CleanupProcedure,AddCleanupProcedure],
	InlineDefs: FROM "InlineDefs"
		USING[LongMult,LongDiv,DIVMOD],
	SegmentDefs: FROM "SegmentDefs",
	StreamDefs: FROM "StreamDefs"
		USING[GetDefaultKey,GetDefaultDisplayStream];

TexIO: PROGRAM
IMPORTS TexStringDefs,
	DisplayDefs,FontDefs,ImageDefs,InlineDefs,SegmentDefs,StreamDefs
EXPORTS TexIODefs =
BEGIN OPEN TexMathDefs,TexDefs,TexIODefs;

in: StreamHandle; -- the current input stream
out: StreamHandle; -- the current output stream
disp: StreamHandle; -- the default display stream

loc,dloc: CARDINAL;

GetStream: PUBLIC PROCEDURE RETURNS[StreamHandle] =
	BEGIN RETURN[out] END;
SetStream: PUBLIC PROCEDURE[stream: StreamHandle] =
	BEGIN
	IF out=disp THEN dloc←loc;
	out←stream; loc←0;
	END;
UseDisplay: PUBLIC PROCEDURE =
	BEGIN out←disp; loc←dloc END;

Wc: PUBLIC PROCEDURE[c: CHARACTER] = -- write a character
	BEGIN
	out.put[out,c];
	IF c=CR THEN loc←0 ELSE loc←loc+1;
	END;

Cr: PUBLIC PROCEDURE = BEGIN Wc[CR] END; -- write a carriage return
Sp: PUBLIC PROCEDURE = BEGIN Wc[SP] END; -- write a space
esc: CHARACTER←'\;
SetEsc: PUBLIC PROCEDURE[c: CHARACTER] = BEGIN esc←c END; -- set esc
Esc: PUBLIC PROCEDURE = BEGIN Wc[esc] END; -- write the escape char

Loc: PUBLIC PROCEDURE RETURNS[CARDINAL] = -- return the current location
	BEGIN RETURN[loc] END;
Tab: PUBLIC PROCEDURE[tloc: CARDINAL] = -- tab over to location tloc
	BEGIN WHILE loc<tloc DO Sp ENDLOOP END;

Ws: PUBLIC PROCEDURE[s: STRING] = -- write a string
	BEGIN
	i: CARDINAL;
	FOR i IN[0..s.length) DO Wc[s[i]] ENDLOOP;
	END;

Wss: PUBLIC PROCEDURE[s: STRING, i1,i2: CARDINAL] = -- write a substring
	BEGIN
	i: CARDINAL;
	FOR i IN[i1..MIN[i2,s.length]) DO Wc[s[i]] ENDLOOP;
	END;


WNum: PROCEDURE[val: UNSPECIFIED, radix: CARDINAL,
	signed: BOOLEAN, columns: CARDINAL] =
	BEGIN OPEN TexStringDefs;
	fill: CHARACTER←(IF radix=10 THEN SP ELSE '0);
	s: STRING ← [7]; -- large enough if smallest radix is 8
	IF signed AND INTEGER[val]<0 THEN
		BEGIN AppendChar[s,'-]; val←-val END;
	AppendNumber[s,val,radix];
	THROUGH (s.length..columns] DO Wc[fill] ENDLOOP;
	Ws[s];
	RETURN
	END;

Wn: PUBLIC PROCEDURE[n: INTEGER] = -- write a signed decimal number
	BEGIN WNum[n,10,TRUE,0] END;

Wnf: PUBLIC PROCEDURE[n: CARDINAL, f: CARDINAL] = -- unsigned decimal, f columns
	BEGIN WNum[n,10,FALSE,f] END;

Wo: PUBLIC PROCEDURE[o: CARDINAL] = -- write an unsigned octal number
	BEGIN WNum[o,10B,FALSE,0] END;

WFont: PUBLIC PROCEDURE[f: Font] =
	BEGIN
	Esc; Wc[':]; Wc['@+f];
	END;

WFChar: PUBLIC PROCEDURE[fc: FChar] =
	BEGIN
	WFont[fc.font]; Sp; Wc[fc.char];
	END;

WCode: PROCEDURE[x: UNSPECIFIED] =
	BEGIN
	Wc['']; WNum[x,8,FALSE,3];
	END;

mfname: ARRAY MFont OF STRING = ["rm","it","sy","ex"];
mfbias: ARRAY MFont OF CARDINAL = [0,200B,400B,600B];

WMFont: PUBLIC PROCEDURE[m: MFont] =
	BEGIN
	Ws[IF m IN MFont THEN mfname[m] ELSE "??"];
	END;

WMChar: PUBLIC PROCEDURE[mchar: MChar] =
	BEGIN
	WMFont[mchar.mfont]; WCode[mchar.char];
	END;


WMCharOctal: PUBLIC PROCEDURE[mchar: MChar] =
	BEGIN
	n: CARDINAL←LOOPHOLE[mchar.char];
	mf: MFont;
	IF (mf←mchar.mfont) IN MFont THEN n←n+mfbias[mf];
	WCode[n];
	END;

WDimn: PUBLIC PROCEDURE[d: Dimn] = -- write value of d in points
	BEGIN OPEN InlineDefs;
	neg: BOOLEAN←(d<0);
	hpts,frac: CARDINAL;
	pts: INTEGER;
	hpts←LongDiv[(LongMult[ABS[d],72*100]+2540/2),2540]; -- hundreths of points
	[pts,frac]←DIVMOD[pts,100];
	Wn[IF neg THEN -pts ELSE pts];
	Wc['.]; WNum[frac,10,FALSE,2];
	END;


-- input procedures

ReadChar: PUBLIC PROCEDURE RETURNS[CHARACTER] =
	BEGIN RETURN[in.get[in]] END;

ControlH: CHARACTER = 'H-100B;
ControlQ: CHARACTER = 'Q-100B;
ControlR: CHARACTER = 'R-100B;
ControlV: CHARACTER = 'V-100B;
ControlW: CHARACTER = 'W-100B;
ControlX: CHARACTER = 'X-100B;
DEL: CHARACTER = 177C;

ReadLine: PUBLIC PROCEDURE[s: STRING] =
	BEGIN
	c: CHARACTER;
	Clear: PROCEDURE[c, oldc: CHARACTER] = --INLINE--
		BEGIN
		WITH out SELECT FROM
			Display => BEGIN clearChar[out,oldc]; loc←loc-1 END;
			ENDCASE => Wc[c];
		END;
	Appnd: PROCEDURE[c: CHARACTER] = --INLINE--
		BEGIN
		TexStringDefs.AppendChar[s,c]; Wc[c];
		END;

	c ← in.get[in];
	s.length ← 0;
	UNTIL c=CR DO SELECT c FROM
		DEL,ControlH => -- clear character
			IF s.length>0 THEN
				BEGIN Clear[c, s[s.length-1]]; s.length ← s.length-1 END;
		ControlW => -- clear word
			BEGIN	-- text to be backed up is of the form
			-- ...<li><v><ti>;	 the <v> and <ti> are to be removed.
			i: CARDINAL;
			state: {ti, v, li} ← ti;
			FOR i DECREASING IN [0..s.length)
				DO
				SELECT s[i] FROM
					IN['A..'Z],IN['a..'z],IN['0..'9] => IF state=ti THEN state←v;
					ENDCASE => IF state=v THEN state←li;
				IF state = li THEN GO TO Done;
				Clear[ControlH, s[i]];
				REPEAT
					Done => s.length ← i+1;
					FINISHED => s.length ← 0;
				ENDLOOP;
			END;
		ControlX => -- clear line
			BEGIN
			WITH out SELECT FROM
				Display => BEGIN clearCurrentLine[out]; loc←0 END;
				ENDCASE => Wc[c];
			s.length ← 0;
			END;
--		ControlV => Appnd[in.get[in]];
		ENDCASE => Appnd[c];
		c ← in.get[in];
		ENDLOOP;
	END;

-- initialization

font: FontDefs.FontHandle←NIL;

GetTexFont: PROCEDURE[name: STRING] =
	BEGIN OPEN SegmentDefs;
	fh: FileHandle;
	seg: FileSegmentHandle;
	fh←NewFile[name, Read, OldFileOnly !FileNameError => GOTO NotThere];
	seg←NewFileSegment[fh, DefaultBase, DefaultPages, Read];
	font←FontDefs.CreateFont[seg];
	EXITS NotThere => RETURN;
	END;

IOCleanupItem: ImageDefs.CleanupItem ← [link:,
	proc: IOCleanupProc,
	mask: ImageDefs.CleanupMask[Restore]];

IOCleanupProc: ImageDefs.CleanupProcedure =
	BEGIN
	SELECT why FROM
		Restore => IF font#NIL THEN DisplayDefs.SetFont[font];
		ENDCASE;
  END;

IOInit: PROCEDURE =
	BEGIN
	in←StreamDefs.GetDefaultKey[];
	out←disp←StreamDefs.GetDefaultDisplayStream[];
	loc←dloc←0;
	GetTexFont["TexFont.al"];
	ImageDefs.AddCleanupProcedure[@IOCleanupItem];
	IOCleanupProc[Restore];
	END;

IOInit;

END.