XFormatImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edit :26-Jun-84 18:39:36, KNguyen
Tim Diebert: December 9, 1986 2:08:29 pm PST
DIRECTORY
Basics USING [BITOR, BITSHIFT, LowHalf, LongDivMod, bitsPerWord, UnsafeBlock],
BasicTime USING [GMT, Now, nullGMT],
Convert USING [RopeFromTime],
IO USING [STREAM, PutBlock],
NSString USING [Character, String],
RefText USING [AppendChar, AppendRope, ObtainScratch, ReleaseScratch, TrustTextAsRope],
Rope USING [Substr, Text, ToRefText],
TTY USING [Handle, Narrow, PutText],
XFormat USING [DateFormat, ErrorCode, FormatProc, Handle, NetFormat, NumberFormat, Object, OctalFormat],
XNS;
XFormatImpl:
CEDAR
MONITOR
IMPORTS Basics, BasicTime, Convert, IO, RefText, Rope, TTY
EXPORTS XFormat =
BEGIN OPEN XFormat, nss: NSString;
Char:
PUBLIC
PROCEDURE [h: Handle, char:
CHAR] = {
rt: REF TEXT ← RefText.ObtainScratch[1];
rt[0] ← char; rt.length ← 1;
IF h = NIL THEN h ← GetDefaults[];
h.proc[rt, h ! UNWIND => RefText.ReleaseScratch[rt]];
RefText.ReleaseScratch[rt];
};
Number:
PUBLIC
PROCEDURE [h: Handle, n:
LONG
UNSPECIFIED, format: NumberFormat] =
BEGIN
s: REF TEXT ← RefText.ObtainScratch[maxDigitLength];
neg: BOOLEAN;
NextDigit:
PROCEDURE [n:
LONG
CARDINAL] = {
lr: LONG CARDINAL;
r: CARDINAL;
[n, lr] ← Basics.LongDivMod[n, format.base];
IF n # 0 THEN NextDigit[n];
IF (r ← Basics.LowHalf[lr]) > 9 THEN r ← r + 'A - '0 - 10;
s ← RefText.AppendChar[s, LOOPHOLE[(r + '0).ORD]];
};
IF h = NIL THEN h ← GetDefaults[];
IF
LOOPHOLE[n,
LONG
INTEGER] < 0
AND format.signed
THEN {
n ← -LOOPHOLE[n, LONG INTEGER]; neg ← TRUE}
ELSE neg ← FALSE;
NextDigit[n];
FormatNumber[w: s, format: format, neg: neg, h: h];
RefText.ReleaseScratch[s];
END;
StreamProc:
PUBLIC FormatProc = {
FormatProc: TYPE = PROCEDURE [r: NSString.String, h: Handle];
stream: IO.STREAM;
IF (stream ← NARROW[h.stream]) = NIL THEN ERROR Error[nilData];
IO.PutBlock[stream, r];
};
TTYProc: PUBLIC FormatProc = {
FormatProc: TYPE = PROCEDURE [r: NSString.String, h: Handle];
tty: TTY.Handle;
IF (tty ← TTY.Narrow[h.stream]) = NIL THEN ERROR Error[nilData];
TTY.PutText[tty, r];
};
WriterProc:
PUBLIC FormatProc = {
IF h.data = NIL THEN ERROR Error[nilData];
XS.AppendReader[to: h.data, from: r];
h.context ← XString.WriterInfo[h.data].endContext;
};
StreamObject:
PUBLIC
PROC [sH:
IO.
STREAM]
RETURNS [Handle] = {
h: Handle ← NEW [Object];
IF sH = NIL THEN ERROR Error[nilData];
h.proc ← StreamProc; h.stream ← sH;
RETURN[h]};
bitsPerPSCharacter: CARDINAL = 2; -- I don't want to think about the dashes
bitsPerOctalCharacter: CARDINAL = 3;
bitsPerHexCharacter: CARDINAL = 4;
minBitsPerCharacter:
CARDINAL =
MIN[
bitsPerPSCharacter, bitsPerOctalCharacter, bitsPerHexCharacter];
maxDigits:
CARDINAL =
MAX[
maxCharsInHostNumber, maxCharsInNetworkNumber, maxCharsInSocketNumber];
Digits: TYPE = ARRAY [0..maxDigits) OF CARDINAL;
Words: TYPE = POINTER TO ARRAY [0..3) OF WORD;
HostNumber:
PUBLIC
PROCEDURE [h: Handle, hostNumber:
XNS.Host, format: NetFormat] =
BEGIN
temp: REF TEXT ← NEW[TEXT[maxCharsInHostNumber]];
host: XNS.Host ← hostNumber;
words: Words;
IF h = NIL THEN h ← GetDefaults[];
TRUSTED { words ← LOOPHOLE[@host]; };
IF hostNumber =
XNS.broadcastHost
THEN temp ← RefText.AppendChar[temp, '*]
ELSE temp ← AppendField[temp, words, SIZE[XNS.Host], format];
h.proc[temp, h];
END;
NetworkNumber:
PUBLIC
PROCEDURE [h: Handle, networkNumber:
XNS.Net,
format: NetFormat] =
BEGIN
temp: REF TEXT ← NEW[TEXT[maxCharsInHostNumber]];
net: XNS.Net ← networkNumber;
words: Words;
IF h = NIL THEN h ← GetDefaults[];
TRUSTED { words ← LOOPHOLE[@net]; };
temp ← AppendField[temp, words, SIZE[XNS.Net], format];
h.proc[temp, h];
END;
SocketNumber:
PUBLIC
PROCEDURE [h: Handle, socketNumber:
XNS.Socket, format: NetFormat] =
TRUSTED
BEGIN
temp: REF TEXT ← NEW[TEXT[maxCharsInHostNumber]];
socket: XNS.Socket ← socketNumber;
words: Words;
IF h = NIL THEN h ← GetDefaults[];
TRUSTED { words ← LOOPHOLE[@socket]; };
temp ← AppendField[temp, words, SIZE[XNS.Socket], format];
h.proc[temp, h];
END;
NetworkAddress:
PUBLIC
PROCEDURE [h: Handle, networkAddress:
XNS.Address, format: NetFormat] =
TRUSTED
BEGIN
temp: REF TEXT ← NEW[TEXT[maxCharsInHostNumber]];
words: Words;
IF h = NIL THEN h ← GetDefaults[];
TRUSTED { words ← LOOPHOLE[@networkAddress.net]; };
temp ← AppendField[temp, words, SIZE[XNS.Address], format];
temp ← RefText.AppendChar[temp, '.];
TRUSTED { words ← LOOPHOLE[@networkAddress.host]; };
IF networkAddress.host =
XNS.broadcastHost
THEN temp ← RefText.AppendChar[temp, '*]
ELSE temp ← AppendField[temp, words, SIZE[XNS.Host], format];
temp ← RefText.AppendChar[temp, '.];
TRUSTED { words ← LOOPHOLE[@networkAddress.socket]; };
temp ← AppendField[temp, words, SIZE[XNS.Socket], format];
h.proc[temp, h];
END;
This will break on a 32 bit machine.
AppendField:
PROC [text:
REF
TEXT, words: Words, count:
NAT, format: NetFormat]
RETURNS [
REF
TEXT] = {
digits: Digits;
base: NAT;
SELECT format
FROM
octal => base ← 8;
productSoftware => base ← 10;
hex => base ← 16;
ENDCASE => ERROR Error[invalidFormat];
TRUSTED {
ConvertToDigits[words, count, base, @digits];
text ← AppendDigits[text, @digits, base = 10]; };
IF base = 16 THEN text ← RefText.AppendChar[text, 'H];
RETURN[text];
};
ConvertToDigits:
PROC [words: Words, size, base:
NAT, digits:
POINTER
TO Digits] =
TRUSTED {
digits^ ← ALL[0];
FOR i:
NAT
IN [0..size*Basics.bitsPerWord)
DO
bit: CARDINAL ← ShiftFieldLeft[words, size, 1];
FOR j:
NAT
DECREASING
IN [0..maxDigits)
DO
digits[j] ← digits[j]*2 + bit;
IF digits[j] >= base THEN { digits[j] ← digits[j] - base; bit ← 1; }
ELSE bit ← 0;
ENDLOOP;
ENDLOOP;
};
ShiftFieldLeft:
PROC [words: Words, count:
NAT, shift:
INTEGER]
RETURNS [left: NAT] = TRUSTED {
right: WORD ← 0;
FOR i:
NAT
DECREASING
IN [0..count)
DO
left ← Basics.BITSHIFT[words[i], shift - 16];
words[i] ← Basics.BITOR[Basics.BITSHIFT[words[i], shift], right];
right ← left;
ENDLOOP;
};
AppendDigits:
PROC [text:
REF
TEXT, digits:
POINTER
TO Digits, dashes:
BOOL]
RETURNS [
REF
TEXT] =
TRUSTED {
something: BOOL ← FALSE;
FOR i:
NAT
IN [0..maxDigits)
DO
v: NAT ← digits[i];
IF dashes
AND something
AND (maxDigits - i)
MOD 3 = 0
THEN
text ← RefText.AppendChar[text, '-];
IF v # 0 AND ~something THEN {
IF dashes
THEN {
SELECT maxDigits - i FROM
1 => text ← RefText.AppendRope[text, "0-00"];
2 => text ← RefText.AppendRope[text, "0-0"];
3 => text ← RefText.AppendRope[text, "0-"];
ENDCASE => NULL; };
IF v > 9 THEN text ← RefText.AppendChar[text, '0]; -- Leading digit for Hex case
something ← TRUE; };
IF something
THEN {
c: CHAR ← IF v > 9 THEN v - 10 + 'A ELSE v + '0;
text ← RefText.AppendChar[text, c]; };
ENDLOOP;
IF ~something THEN text ← RefText.AppendChar[text, '0];
RETURN[text];
};