-- TexString.mesa

-- last written by Doug Wyatt, September 21, 1979  11:52 AM

DIRECTORY
	TexMemDefs: FROM "TexMemDefs",
	TexStringDefs: FROM "TexStringDefs",
	InlineDefs: FROM "InlineDefs"
		USING [DIVMOD],
	StreamDefs: FROM "StreamDefs"
		USING [StreamHandle,StreamObject,StreamError],
	SystemDefs: FROM "SystemDefs"
		USING [AllocateHeapNode,FreeHeapNode];

TexString: PROGRAM IMPORTS TexMemDefs,InlineDefs,StreamDefs,SystemDefs
EXPORTS TexStringDefs =
BEGIN OPEN StreamDefs,TexStringDefs;

StringFull: PUBLIC SIGNAL[oldstring: STRING]
	RETURNS[newstring: STRING] = CODE;

CreateStringStream: PUBLIC PROCEDURE[string: STRING]
	RETURNS[StringHandle] =
	BEGIN
	stream: StringHandle←SystemDefs.AllocateHeapNode[SIZE[Other StreamObject]];
	stream↑←[reset: SSReset, get: SSGet, putback: SSPutBack,
		put: SSPut, endof: SSEndof, destroy: SSDestroy,
		link: NIL, body: Other[type: 0, data: string]];
	RETURN[stream];
	END;

SSReset: PROCEDURE[stream: StreamHandle] =
	BEGIN
	WITH s:stream SELECT FROM
		Other => LOOPHOLE[s.data,STRING].length←0;
		ENDCASE => SIGNAL StreamError[@s, StreamType];
	END;

SSGet: PROCEDURE[stream: StreamHandle] RETURNS[UNSPECIFIED] =
	BEGIN
	WITH s:stream SELECT FROM
		Other => SIGNAL StreamError[@s, StreamOperation]; -- get not implemented
		ENDCASE => SIGNAL StreamError[@s, StreamType];
	RETURN[0C];
	END;

SSPutBack: PROCEDURE[stream: StreamHandle, item: UNSPECIFIED] =
	BEGIN
	WITH s:stream SELECT FROM
		Other => SIGNAL StreamError[@s, StreamOperation];
		ENDCASE => SIGNAL StreamError[@s, StreamType];
	END;

SSPut: PROCEDURE[stream: StreamHandle, item: UNSPECIFIED] =
	BEGIN
	WITH s:stream SELECT FROM
		Other => AppendChar[LOOPHOLE[s.data,STRING],item];
		ENDCASE => SIGNAL StreamError[@s, StreamType];
	END;

SSEndof: PROCEDURE[stream: StreamHandle] RETURNS[BOOLEAN] =
	BEGIN
	WITH s:stream SELECT FROM
		Other =>
			BEGIN
			string: STRING=s.data;
			RETURN[string.length~<string.maxlength];
			END;
		ENDCASE => BEGIN SIGNAL StreamError[@s, StreamType]; RETURN[FALSE] END;
	END;

SSDestroy: PROCEDURE[stream: StreamHandle] =
	BEGIN
	WITH s:stream SELECT FROM
		Other => SystemDefs.FreeHeapNode[@s];
		ENDCASE => SIGNAL StreamError[@s, StreamType];
	END;


AppendChar: PUBLIC PROCEDURE[s: STRING, c: CHARACTER] =
	BEGIN
	i: CARDINAL;
	UNTIL (i←s.length)<s.maxlength DO s←SIGNAL StringFull[s] ENDLOOP;
	s[i]←c; s.length←i+1;
	END;

AppendString: PUBLIC PROCEDURE[s1: STRING, s2: STRING] =
	BEGIN
	i: CARDINAL;
	FOR i IN[0..s2.length) DO AppendChar[s1,s2[i]] ENDLOOP;
	END;

AppendNumber: PUBLIC PROCEDURE[s: STRING, val: CARDINAL, radix: CARDINAL] =
	BEGIN
	xn: PROCEDURE [n: CARDINAL] =
		BEGIN
		r: CARDINAL;
		[n,r] ← InlineDefs.DIVMOD[n,radix];
		IF n # 0 THEN xn[n];
		IF r>9 THEN r ← r + 'A-'0-10;
		AppendChar[s, r+'0];
		END;
	xn[val];
	END;

CopyString: PUBLIC PROCEDURE[old: STRING] RETURNS[new: STRING] =
	BEGIN
	new←TexMemDefs.AllocString[old.length];
	AppendString[new,old];
	END;

EqualString: PUBLIC PROCEDURE[s,t: STRING] RETURNS[BOOLEAN] =
	BEGIN
	i: CARDINAL;
	IF s.length=t.length THEN FOR i IN[0..s.length)
		DO IF s[i]#t[i] THEN EXIT REPEAT FINISHED => RETURN[TRUE] ENDLOOP;
	RETURN[FALSE];
	END;

END.