TTYImpl.mesa
Copyright Ó 1983, 1984, 1986, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: January 6, 1987 5:08:53 pm PST
DIRECTORY
Ascii USING [BS, ControlA, ControlQ, ControlR, ControlV, ControlW, ControlX, CR, DEL, FF, SP, TAB],
Basics USING [UnsafeBlock, HighByte, HighHalf, LowByte, LowHalf, RawBytes],
Convert USING [IntFromRope, RopeFromInt],
IO,
Process USING [Abort, DisableTimeout, EnableAborts],
PrincOpsUtils USING [IsBound],
RefText USING [Append, ObtainScratch, ReleaseScratch, TrustTextAsRope],
Rope USING [ROPE, ToRefText],
TTY USING [CharStatus, CreateTTYInstance, -- DateFormat, -- EchoClass, Handle --, NumberFormat-- ],
TTYConstants,
TTYStream USING [SendAttention, SetSST, SubSequenceType, WaitAttention];
TTYImpl:
MONITOR
LOCKS h
USING h: Handle
IMPORTS Basics, Convert, IO, PrincOpsUtils, Process, RefText, Rope, TTY, TTYStream
EXPORTS TTY = BEGIN
Handle: PUBLIC TYPE = REF Object;
Object:
PUBLIC
TYPE =
MONITORED
RECORD [
stream: IO.STREAM ← NIL,
echo: TTY.EchoClass ← plain,
newline: BOOLEAN ← TRUE,
inputAborted: BOOLEAN ← FALSE,
next: Handle,
buffer: Q ← Init[],
backingStream: IO.STREAM ← NIL,
altStream: AltHandle ← NIL,
inputProcess: PROCESS ← NIL,
inputCondition: CONDITION,
tty: TTY.Handle ← NIL];
AltHandle: PUBLIC TYPE = REF AltObject;
AltObject: TYPE = RECORD [s: IO.STREAM, next: AltHandle];
OutOfInstances: PUBLIC ERROR = CODE;
NoDefaultInstance: PUBLIC ERROR = CODE;
aborted: BYTE = TTYConstants.aborted;
notAborted: BYTE = TTYConstants.notAborted;
normal: TTYStream.SubSequenceType = TTYConstants.normal;
setBackingSize: TTYStream.SubSequenceType = TTYConstants.setBackingSize;
removeChars: TTYStream.SubSequenceType = TTYConstants.removeChars;
blinkDisplay: TTYStream.SubSequenceType = TTYConstants.blinkDisplay;
Create:
PUBLIC
SAFE
PROCEDURE [name: Rope.
ROPE ←
NIL,
backingStream, ttyImpl:
IO.
STREAM ←
NIL]
RETURNS [h: Handle] =
TRUSTED {
h ← NEW[Object ← [stream: NIL, backingStream: NIL, next: list]];
IF ttyImpl =
NIL
THEN
SELECT PrincOpsUtils.IsBound[
LOOPHOLE[
TTY.CreateTTYInstance]]
FROM
TRUE => [ttyImpl, backingStream] ← TTY.CreateTTYInstance[name, backingStream, h.tty];
FALSE => ERROR NoDefaultInstance;
ENDCASE;
h.backingStream ← backingStream;
h.stream ← ttyImpl;
list ← h;
Process.DisableTimeout[@h.inputCondition];
Process.EnableAborts[@h.inputCondition];
h.inputProcess ← FORK ListenForInput[h]};
Destroy:
PUBLIC
SAFE
PROC [h: Handle, deleteBackingFile:
BOOLEAN ←
FALSE] =
TRUSTED {
P:
ENTRY
PROCEDURE [h: Handle] = {
ENABLE UNWIND => NULL;
IF list = h
THEN list ← h.next
ELSE
FOR l: Handle ← list, l.next
UNTIL l.next =
NIL
DO
IF l.next = h THEN {l.next ← l.next.next; EXIT}; ENDLOOP;
IF ~IsEmpty[h.buffer] THEN Empty[h.buffer]};
TTYStream.SetSST[h.stream, TTYConstants.deleteBackingFile];
TTYStream.SetSST[h.stream, normal];
Process.Abort[h.inputProcess];
JOIN h.inputProcess;
P[h];
IO.Close[h.stream];
};
ListenForInput:
PROCEDURE [h: Handle] =
TRUSTED
BEGIN
DoIt:
ENTRY
PROCEDURE [h: Handle] = {
ENABLE UNWIND => NULL;
wakeUp: BOOLEAN = IsEmpty[h.buffer];
BlockToQR[block, h.buffer];
IF wakeUp THEN BROADCAST h.inputCondition};
AbortClient:
ENTRY
PROCEDURE [h: Handle] = {
h.inputAborted ← TRUE; BROADCAST h.inputCondition};
blockSize: CARDINAL = 20;
block: Basics.UnsafeBlock;
storage: PACKED ARRAY [0..blockSize) OF BYTE;
block ← [base: LOOPHOLE[LONG[@storage]], startIndex: 0, count: blockSize];
DO
block.count ← blockSize;
block.count ← IO.UnsafeGetBlock[h.stream, block ! ABORTED => EXIT];
DoIt[h];
ENDLOOP;
AbortClient[h];
END;
GetEcho:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle]
RETURNS [
TTY.EchoClass] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h]; RETURN[h.echo]};
SetEcho:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle, new:
TTY.EchoClass]
RETURNS [old:
TTY.EchoClass] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h]; old ← h.echo; h.echo ← new};
CharsAvailable:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle]
RETURNS [
CARDINAL] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h]; RETURN[Count[h.buffer]];
-- note that this count is incorrect if there are alternate input streams --};
GetChar:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle]
RETURNS [c:
CHARACTER] =
TRUSTED {
ENABLE UNWIND => NULL;
advanceAltStream: BOOLEAN ← FALSE;
temp: AltHandle;
WHILE h.altStream #
NIL
DO
c ← IO.GetChar[h.altStream.s ! IO.EndOfStream => {advanceAltStream ← TRUE; CONTINUE}];
IF ~advanceAltStream THEN RETURN[c];
IO.Close[h.altStream.s];
temp ← h.altStream; h.altStream ← h.altStream.next;
advanceAltStream ← FALSE;
ENDLOOP;
WHILE IsEmpty[h.buffer] DO InternalCheckState[h]; WAIT h.inputCondition ENDLOOP;
c ← GetF[h.buffer]};
PopAlternateInputStreams:
PUBLIC
ENTRY
SAFE
PROC [h: Handle, howMany:
CARDINAL ← 1] =
TRUSTED
BEGIN
ENABLE UNWIND => NULL;
temp: AltHandle;
FOR i:
CARDINAL
IN [0..howMany)
WHILE h.altStream #
NIL
DO
IO.Close[h.altStream.s];
temp ← h.altStream; h.altStream ← h.altStream.next;
ENDLOOP;
END;
PushAlternateInputStream:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle, stream:
IO.
STREAM] =
TRUSTED
BEGIN
ENABLE UNWIND => NULL;
h.altStream ← NEW[AltObject ← [s: stream, next: h.altStream]];
END;
PutBackChar:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle, c:
CHARACTER] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h]; PutR[h.buffer, c];
-- note that this does not work if there are alternate input streams --};
ResetUserAbort:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h];
TTYStream.SendAttention[h.stream, notAborted]};
UserAbort:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle]
RETURNS [
BOOLEAN] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h];
RETURN[
SELECT TTYStream.WaitAttention[h.stream]
FROM
aborted => TRUE,
ENDCASE => FALSE]};
SetUserAbort:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h]; TTYStream.SendAttention[h.stream, aborted]};
BlinkDisplay:
PUBLIC
SAFE
PROC [h: Handle] =
TRUSTED {
CheckState[h];
TTYStream.SetSST[h.stream, blinkDisplay];
TTYStream.SetSST[h.stream, normal]};
NewLine:
PUBLIC
ENTRY
SAFE
PROCEDURE [h: Handle]
RETURNS [
BOOLEAN] =
TRUSTED {
ENABLE UNWIND => NULL;
InternalCheckState[h]; RETURN[h.newline]};
PutChar:
PUBLIC
SAFE
PROC [h: Handle, c:
CHARACTER] =
TRUSTED {
P:
ENTRY
PROCEDURE [h: Handle] = {
ENABLE UNWIND => NULL; h.newline ← c = Ascii.CR};
CheckState[h];
P[h];
IO.PutChar[h.stream, c]};
PutString,
PutLongString,
PutText:
PROCEDURE [h: Handle, s:
REF
TEXT] =
TRUSTED {
P:
ENTRY
PROCEDURE [h: Handle] = {
ENABLE UNWIND => NULL;
h.newline ← s[s.length - 1] = Ascii.CR};
CheckState[h];
IF s = NIL THEN RETURN;
IO.UnsafePutBlock[h.stream, [LOOPHOLE[@s.text], 0, s.length]];
P[h]};
RemoveCharacter,
RemoveCharacters:
PUBLIC
SAFE
PROC [h: Handle, n:
CARDINAL] =
TRUSTED {
CheckState[h];
TTYStream.SetSST[h.stream, removeChars];
IO.PutChar[h.stream, LOOPHOLE[Basics.HighByte[n]]];
IO.PutChar[h.stream, LOOPHOLE[Basics.LowByte[n]]];
TTYStream.SetSST[h.stream, normal]};
Backing Files
NoBackingFile: PUBLIC ERROR = CODE;
BackingStream:
PUBLIC
SAFE
PROC [h: Handle]
RETURNS [
IO.
STREAM] =
TRUSTED {
CheckState[h]; RETURN[h.backingStream]};
SetBackingSize:
PUBLIC
SAFE
PROC [h: Handle, size:
LONG
CARDINAL] =
TRUSTED {
lowHalf, highHalf: CARDINAL;
CheckState[h];
highHalf ← Basics.HighHalf[size];
lowHalf ← Basics.LowHalf[size];
TTYStream.SetSST[h.stream, setBackingSize];
IO.PutChar[h.stream, LOOPHOLE[Basics.HighByte[highHalf]]];
IO.PutChar[h.stream, LOOPHOLE[Basics.LowByte[highHalf]]];
IO.PutChar[h.stream, LOOPHOLE[Basics.HighByte[lowHalf]]];
IO.PutChar[h.stream, LOOPHOLE[Basics.LowByte[lowHalf]]];
TTYStream.SetSST[h.stream, normal]};
Basic input
GetDecimal:
PUBLIC
SAFE
PROC [h: Handle]
RETURNS [i:
INTEGER] =
TRUSTED {
s: REF TEXT ← RefText.ObtainScratch[10];
CheckState[h];
[] ← GetEditedString[h, s, IsAtom];
i ← Convert.IntFromRope[RefText.TrustTextAsRope[s], 10];
RefText.ReleaseScratch[s];
RETURN[i]};
GetID:
PUBLIC
SAFE
PROC [h: Handle, s:
REF
TEXT] =
TRUSTED {
CheckState[h]; [] ← GetEditedString[h, s, IsAtom]};
GetLine:
PUBLIC
SAFE
PROC [h: Handle, s:
REF
TEXT] =
TRUSTED {
CheckState[h]; [] ← GetEditedString[h, s, IsCR]; PutChar[h, Ascii.CR]};
GetPassword:
PUBLIC
SAFE
PROC [h: Handle, s:
REF
TEXT] =
TRUSTED {
old: TTY.EchoClass;
CheckState[h];
old ← SetEcho[h, stars];
IF old = none THEN [] ← SetEcho[h, none];
[] ← GetEditedString[h, s, IsAtom ! UNWIND => [] ← SetEcho[h, old]];
[] ← SetEcho[h, old]};
GetLongDecimal:
PUBLIC
SAFE
PROC [h: Handle]
RETURNS [n:
INT] =
TRUSTED {
s: REF TEXT ← RefText.ObtainScratch[32];
CheckState[h];
[] ← GetEditedString[h, s, IsAtom];
n ← Convert.IntFromRope[RefText.TrustTextAsRope[s], 10];
RefText.ReleaseScratch[s];
RETURN[n]};
GetLongNumber:
PUBLIC
SAFE
PROC [h: Handle, default:
LONG
UNSPECIFIED,
radix:
CARDINAL, showDefault:
BOOLEAN]
RETURNS [n:
LONG
UNSPECIFIED] =
TRUSTED {
s: REF TEXT ← RefText.ObtainScratch[32];
r: REF TEXT ← RefText.ObtainScratch[32];
CheckState[h];
IF showDefault
THEN {
IF radix = 10
AND
LOOPHOLE[default,
LONG
INTEGER] < 0
THEN {s[0] ← '-; s.length ← 1; default ← -default};
r ← Rope.ToRefText[Convert.RopeFromInt[default, radix]];
s ← RefText.Append[s, r, radix]};
IF radix = 8 THEN String.AppendChar[s, 'B]}; -- Done by Convert.RopeFromInt
[] ← GetEditedString[h, s, IsAtom];
n ← Convert.IntFromRope[RefText.TrustTextAsRope[s], 10];
RefText.ReleaseScratch[s];
RefText.ReleaseScratch[r];
RETURN[n]};
GetLongOctal:
PUBLIC
SAFE
PROC [h: Handle]
RETURNS [n:
LONG
UNSPECIFIED] =
TRUSTED {
s: REF TEXT ← RefText.ObtainScratch[32];
CheckState[h];
[] ← GetEditedString[h, s, IsAtom];
n ← Convert.IntFromRope[RefText.TrustTextAsRope[s], 8];
RefText.ReleaseScratch[s];
RETURN[n]};
GetNumber:
PUBLIC
SAFE
PROC [h: Handle, default:
UNSPECIFIED, radix:
CARDINAL,
showDefault:
BOOLEAN]
RETURNS [n:
UNSPECIFIED] =
TRUSTED {
sDefault: LONG UNSPECIFIED ← LONG[default];
result: LONG UNSPECIFIED;
result ← GetLongNumber[h, sDefault, radix, showDefault];
n ← Basics.LowHalf[LOOPHOLE[result]];
RETURN[n]};
GetOctal:
PUBLIC
SAFE
PROC [h: Handle]
RETURNS [n:
UNSPECIFIED] =
TRUSTED {
result: LONG UNSPECIFIED;
result ← GetLongOctal[h];
n ← Basics.LowHalf[LOOPHOLE[result]];
RETURN[n]};
GetString:
PUBLIC
SAFE
PROC [h: Handle, s:
REF
TEXT,
t:
PROCEDURE [c:
CHARACTER]
RETURNS [status:
TTY.CharStatus]] =
TRUSTED {
CheckState[h]; PutChar[h, GetEditedString[h, s, t]]};
LineOverflow: PUBLIC SAFE SIGNAL [s: REF TEXT] RETURNS [ns: REF TEXT] = CODE;
Rubout: PUBLIC SAFE SIGNAL = CODE;
GetEditedString:
PUBLIC
SAFE
PROC [h: Handle, s:
REF
TEXT,
t:
PROCEDURE [c:
CHARACTER]
RETURNS [status:
TTY.CharStatus]]
RETURNS [c:
CHARACTER] =
TRUSTED {
WeirdEcho:
PROCEDURE [c:
CHARACTER] = {
SELECT GetEcho[h]
FROM
none => NULL;
plain => PutChar[h, c];
stars => PutChar[h, '*]
ENDCASE};
WeirdErase:
PROCEDURE [c:
CHARACTER] = {
SELECT GetEcho[h]
FROM
none => NULL;
plain =>RemoveCharacters[h,
SELECT c
FROM
Ascii.CR, Ascii.BS, Ascii.FF => 0,
IN [0C..Ascii.SP) => 2,
IN [Ascii.SP..'~] => 1,
Ascii.TAB => 1, -- ARGH!!!!!!
ENDCASE => 0];
stars => RemoveCharacter[h, 1]
ENDCASE};
WeirdPutString:
PROCEDURE =
INLINE {
FOR i: CARDINAL IN [0..s.length) DO WeirdEcho[s[i]] ENDLOOP};
KillString:
PROCEDURE = {
FOR i: CARDINAL DECREASING IN [0..s.length) DO WeirdErase[s[i]] ENDLOOP;
s.length ← 0};
firstChar: BOOLEAN ← TRUE;
CheckState[h];
WeirdPutString[]; -- show whatever default string is passed in, if any
DO
SELECT t[c ← GetChar[h]]
FROM
stop => RETURN;
ignore => LOOP;
ok =>
SELECT c
FROM
Ascii.DEL => SIGNAL Rubout;
Ascii.ControlA, Ascii.
BS =>
-- backspace
IF s.length > 0 THEN WeirdErase[s[s.length ← s.length - 1]];
Ascii.ControlW, Ascii.ControlQ => {
-- backword
text to be backed up is of the form ...<li><v><ti>, the <v> and <ti> are to be removed.
state: {ti, v, li} ← ti;
FOR i:
CARDINAL
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;
WeirdErase[s[i]];
REPEAT Done => s.length ← i + 1; FINISHED => s.length ← 0;
ENDLOOP};
Ascii.ControlX => KillString[];
Ascii.ControlR => {
-- refresh--
IF GetEcho[h] # none THEN {PutChar[h, Ascii.CR]; WeirdPutString[]};
LOOP};
Ascii.ControlV => {
-- dont parse next char
IF firstChar THEN KillString[];
WHILE s.length >= s.maxLength DO s ← SIGNAL LineOverflow[s] ENDLOOP;
WeirdEcho[s[s.length] ← c ← GetChar[h]];
s.length ← s.length + 1};
ENDCASE => {
IF firstChar THEN KillString[];
WHILE s.length >= s.maxLength DO s ← SIGNAL LineOverflow[s] ENDLOOP;
WeirdEcho[s[s.length] ← c];
s.length ← s.length + 1};
ENDCASE;
firstChar ← FALSE;
ENDLOOP};
IsAtom:
PROCEDURE [c:
CHARACTER]
RETURNS [
TTY.CharStatus] = {
RETURN[IF c = Ascii.SP OR c = Ascii.CR THEN stop ELSE ok]};
IsCR:
PROCEDURE [c:
CHARACTER]
RETURNS [
TTY.CharStatus] = {
RETURN[IF c = Ascii.CR THEN stop ELSE ok]};
CheckState:
ENTRY
PROCEDURE [h: Handle] =
INLINE {
ENABLE UNWIND => NULL;
IF h.inputAborted THEN ERROR ABORTED};
InternalCheckState:
PROCEDURE [h: Handle] =
INLINE {
IF h.inputAborted THEN ERROR ABORTED};
extended output procedures
OutString:
PROCEDURE [s:
REF
TEXT, clientData: Handle] = {
P:
ENTRY
PROCEDURE [h: Handle] = {
ENABLE UNWIND => NULL;
h.newline ← s[s.length - 1] = Ascii.CR};
IF s = NIL THEN RETURN;
IO.UnsafePutBlock[clientData.stream, [LOOPHOLE[@s.text, LONG POINTER] + SIZE[TEXT[0]], 0, s.length]];
P[clientData]};
PutBlank,
PutBlanks:
PUBLIC
SAFE
PROC [h: Handle, n:
CARDINAL] =
TRUSTED {
s: REF TEXT ← RefText.ObtainScratch[n*2];
CheckState[h];
FOR i: CARDINAL IN [0 .. s.maxLength) DO s[i] ← ' ; ENDLOOP;
s.length ← n;
OutString[s, h];
RefText.ReleaseScratch[s]};
PutBlock:
PUBLIC
SAFE
PROC [h: Handle, block: Basics.UnsafeBlock] =
TRUSTED {
CheckState[h];
IO.UnsafePutBlock[h.stream, block]};
PutDate: PUBLIC SAFE PROC [h: Handle, gmt: Time.Packed, format: TTY.DateFormat,
zone: Time.TimeZoneStandard] = TRUSTED {CheckState[h]};
CheckState[h]; Format.Date[OutString, gmt, format, zone, h]};
PutDecimal:
PUBLIC
SAFE
PROC [h: Handle, n:
INTEGER] =
TRUSTED {
CheckState[h];
IO.PutF[h.stream, "%g", IO.int[n]]};
PutLine:
PUBLIC
SAFE
PROC [h: Handle, s:
REF
TEXT] =
TRUSTED {
CheckState[h]; PutString[h, s]; PutChar[h, Ascii.CR]};
PutLongDecimal:
PUBLIC
SAFE
PROC [h: Handle, n:
LONG
INTEGER] =
TRUSTED {
CheckState[h];
IO.PutF1[h.stream, "%g", IO.int[n]]};
PutLongNumber: PUBLIC SAFE PROC [h: Handle, n: LONG UNSPECIFIED,
format: TTY.NumberFormat] = TRUSTED {CheckState[h]};
CheckState[h];
Format.LongNumber[OutString, n, format, h]};
PutLongOctal: PUBLIC SAFE PROC [h: Handle, n: LONG UNSPECIFIED] = TRUSTED {
CheckState[h]};
CheckState[h]; Format.LongOctal[OutString, n, h]};
PutNumber: PUBLIC SAFE PROC [h: Handle, n: UNSPECIFIED, format: TTY.NumberFormat] = TRUSTED {
CheckState[h]};
Format.Number[OutString, n, format, h]};
PutOctal: PUBLIC SAFE PROC [h: Handle, n: UNSPECIFIED] = TRUSTED {
CheckState[h]};
Format.Octal[OutString, n, h]};
PutLongSubString, PutSubString: PUBLIC SAFE PROC [
h: Handle, ss: String.SubString] = TRUSTED {
CheckState[h]; Format.SubString[OutString, ss, h]};
BYTE: PRIVATE TYPE = [0..255];
QHead: TYPE = RECORD [front, rear: REF QElement];
NullQHead: QHead = [NIL, NIL];
QElement:
PRIVATE
TYPE =
RECORD [
flink, rlink: REF QElement ← NIL,
front, rear: CARDINAL ← 0,
data: PACKED SEQUENCE maxLen: CARDINAL OF BYTE];
pQE: PRIVATE TYPE = REF QElement;
defaultElementSize: PRIVATE CARDINAL = 20;
EmptyQ: SAFE SIGNAL [q: Q] = CODE;
Count:
PROCEDURE [q: Q]
RETURNS [elements:
CARDINAL ← 0] =
BEGIN
IF q = NIL THEN RETURN;
FOR qp: pQE ← q.front, qp.flink
UNTIL qp =
NIL
DO
elements ← elements +
(IF qp.front > qp.rear THEN qp.maxLen - qp.front + qp.rear + 1 ELSE qp.rear - qp.front + 1);
ENDLOOP;
RETURN
END;
IsEmpty:
PROCEDURE [q: Q]
RETURNS [
BOOLEAN] = {
RETURN[q = NIL OR q.front = NIL]};
Empty:
PROCEDURE [q: Q] =
BEGIN
UNTIL IsEmpty[q]
DO
qf: pQE ← q.front;
nqf: pQE = qf.flink;
z.FREE[@qf];
IF nqf = NIL THEN q.rear ← NIL ELSE nqf.rlink ← NIL;
q.front ← nqf;
ENDLOOP;
RETURN
END;
Init: PROCEDURE RETURNS [Q] = {RETURN[NIL]};
GetF:
PROCEDURE [q: Q]
RETURNS [i:
UNSPECIFIED [0..255]] =
BEGIN
qf: pQE;
qff: CARDINAL;
IF q = NIL OR q.front = NIL THEN {SIGNAL EmptyQ[q]; RETURN[0]};
qf ← q.front;
i ← qf[qff ← qf.front];
IF qf.front = qf.rear
THEN BEGIN
-- element empty
nf: pQE = qf.flink;
IF nf = NIL THEN q.rear ← NIL ELSE nf.rlink ← NIL;
z.FREE[@qf];
q.front ← nf;
END
ELSE BEGIN qff ← IF qff = qf.maxLen - 1 THEN 0 ELSE qff + 1; qf.front ← qff; END;
RETURN
END;
GetR:
PROCEDURE [q: Q]
RETURNS [i:
UNSPECIFIED [0..255]] =
BEGIN
qr: pQE;
qrr: CARDINAL;
IF q = NIL OR q.rear = NIL THEN {SIGNAL EmptyQ[q]; RETURN[0]};
qr ← q.rear;
i ← qr[qrr ← qr.rear];
IF qr.rear = qr.front
THEN BEGIN
-- element empty
nr: pQE = qr.rlink;
IF nr = NIL THEN q.front ← NIL ELSE nr.flink ← NIL;
z.FREE[@qr];
q.rear ← nr;
END
ELSE BEGIN qrr ← IF qrr = 0 THEN qr.maxLen - 1 ELSE qrr - 1; qr.rear ← qrr; END;
RETURN
END;
PutR:
PROCEDURE [q: Q, i:
UNSPECIFIED [0..255]] =
BEGIN
qr: pQE;
qrr: CARDINAL;
IF q = NIL THEN RETURN;
qr ← q.rear;
IF qr =
NIL
OR FullElement[qr]
THEN BEGIN
nr: pQE ← NEW[QElement[defaultElementSize]];
nr.rlink ← qr;
IF qr = NIL THEN q.front ← nr ELSE qr.flink ← nr;
q.rear ← qr ← nr;
qrr ← 0;
END
ELSE qrr ← IF qr.rear = qr.maxLen - 1 THEN 0 ELSE qr.rear + 1;
qr[qrr] ← i;
qr.rear ← qrr;
RETURN
END;
BlockToQR:
PROCEDURE [block: Basics.UnsafeBlock, q: Q] =
BEGIN
FOR i:
INT
IN [block.startIndex..block.startIndex+block.count)
DO
base: LONG POINTER TO Basics.RawBytes ← LOOPHOLE[block.base];
PutR[q, base[i]] ENDLOOP;
END;
FullElement:
PROCEDURE [qe: pQE]
RETURNS [
BOOLEAN] = {
OPEN qe;
RETURN[(IF rear < front THEN maxLen + rear - front ELSE rear - front) = maxLen - 1]};