TermCapsImpl.Mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Last Edited by: Spreitzer, March 13, 1985 11:21:30 pm PST
DIRECTORY Ascii, Basics, BasicTime, Convert, FS, IO, OrderedSymbolTableRef, Real, Rope, TermCaps;
TermCapsImpl: CEDAR PROGRAM
IMPORTS Ascii, BasicTime, Convert, FS, IO, OrderedSymbolTableRef, Real, Rope
EXPORTS TermCaps
= {OPEN TermCaps;
cancel: PUBLIC Val ¬ NEW [ROPE ¬ "cancel"];
Bitch: SIGNAL [fmt: ROPE, v1: IO.Value ¬ [null[]]] = CODE;
Busted: ERROR = CODE;
termCaps: SymbolTable ¬ NIL;
defaultTerm: Term ¬ NIL;
EnumerateCaps: PUBLIC PROC [term: Term, consume: PROC [cap: Cap] RETURNS [stop: BOOL]] = {
ExceptNone: PROC [cap: Cap] RETURNS [e: BOOL] = {e ¬ FALSE};
Work: PROC [term: Term, except: PROC [cap: Cap] RETURNS [BOOL]] = {
ExceptMine: PROC [cap: Cap] RETURNS [e: BOOL] = {
IF term.caps.Lookup[cap] # NIL THEN RETURN [TRUE];
e ¬ except[cap]};
PerCap: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
cap: Cap ¬ NARROW[ra];
stop ¬ FALSE;
IF cap.val = cancel THEN RETURN;
IF except[cap] THEN RETURN;
stop ¬ consume[cap];
};
term.caps.EnumerateIncreasing[PerCap];
IF term.default # NIL THEN Work[term.default, ExceptMine];
};
Work[term, ExceptNone];
};
GetCap: PUBLIC PROC [term: Term, name: ROPE, default: Val ¬ NIL] RETURNS [val: Val] = {
cap: Cap ¬ NARROW[term.caps.Lookup[name]];
IF cap # NIL THEN RETURN [IF cap.val = cancel THEN default ELSE cap.val];
IF term.default # NIL THEN val ¬ GetCap[term.default, name, default] ELSE val ¬ default;
};
GetTerm: PUBLIC PROC [tc: TermCap, name: ROPE] RETURNS [term: Term] = {
term ¬ AntiAlias[tc.contents.Lookup[name]];
};
TCTerm: PROC [tc: TermCap, name: ROPE] RETURNS [term: Term] = {
term ¬ AntiAlias[tc.contents.Lookup[name]];
IF term = NIL THEN {
a: Alias ¬ NEW [AliasRep ¬ [
name: name,
val: term ¬ NEW [TermRep ¬ [
names: LIST[name],
caps: OrderedSymbolTableRef.CreateTable[CompareCaps],
default: defaultTerm]]
]];
tc.contents.Insert[a];
};
};
EnumerateTerms: PUBLIC PROC [tc: TermCap, consume: PROC [term: Term] RETURNS [stop: BOOL]] = {
PerAlias: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
a: Alias ¬ NARROW[ra];
IF NOT (a.name = a.val.names.first) THEN RETURN [FALSE];
stop ¬ consume[a.val];
};
tc.contents.EnumerateIncreasing[PerAlias];
};
GetTermCap: PUBLIC PROC [fileName: ROPE, wDir: ROPE ¬ NIL] RETURNS [tc: TermCap] = {
gName: ROPE;
created: GMT;
exists: BOOL ¬ TRUE;
rfi: REF FileID;
from: IO.STREAM;
[fullFName: gName, created: created] ¬ FS.FileInfo[name: fileName, wDir: wDir !FS.Error => {exists ¬ FALSE; CONTINUE}];
IF NOT exists THEN RETURN [NIL];
rfi ¬ NEW [FileID ¬ [gName, created]];
tc ¬ NARROW[termCaps.Lookup[rfi]];
IF tc # NIL THEN RETURN [tc];
tc ¬ NEW [TermCapRep ¬ [
fileID: rfi­,
contents: OrderedSymbolTableRef.CreateTable[CompareTerms]
]];
from ¬ FS.StreamOpen[gName];
termCaps.Insert[tc];
ParseTermCap[from, tc !
Bitch => {
tc.complaints ¬ tc.complaints.Cat[
IO.PutFR[
Rope.Cat["At %g[%g]: ", fmt, "\n"],
IO.rope[gName],
IO.int[from.GetIndex[]],
v1]
];
RESUME;
};
IO.EndOfStream => CONTINUE;
];
};
ParseTermCap: PROC [from: IO.STREAM, tc: TermCap] = {
atStart: BOOL ¬ TRUE;
DO
ENABLE Busted => {Bitch["busted"]; LOOP};
term: Term ¬ NIL;
names: RopeList ¬ NIL;
nameCount: NAT ¬ 0;
bestName: ROPE ¬ NIL;
First, look for begin of entry: a line starting with alphabetic
DO
char: CHAR;
IF atStart THEN atStart ¬ FALSE ELSE [] ¬ from.GetLineRope[];
char ¬ from.PeekChar[];
SELECT char FROM
IN ['a .. 'z], IN ['A .. 'Z] => EXIT;
ENDCASE;
ENDLOOP;
Next, parse names
DO
name, sep: ROPE;
namedTerm: Term;
name ¬ from.GetTokenRope[TermNameBuster].token;
IF name.Equal["|"] THEN {Bitch["empty name"]; LOOP};
IF name.Equal[":"] THEN {Bitch["empty name"]; EXIT};
nameCount ¬ nameCount + 1;
IF nameCount <= 2 THEN bestName ¬ name;
namedTerm ¬ GetTerm[tc, name];
IF namedTerm = term THEN NULL
ELSE IF term = NIL THEN term ¬ namedTerm
ELSE IF namedTerm # NIL THEN Bitch["term name collision on %g", IO.rope[name]];
IF namedTerm = NIL THEN names ¬ CONS[name, names];
sep ¬ from.GetTokenRope[TermNameBuster].token;
IF sep.Equal[":"] THEN EXIT;
IF NOT sep.Equal["|"] THEN ERROR;
ENDLOOP;
IF term = NIL THEN term ¬ NEW [TermRep ¬ [
caps: OrderedSymbolTableRef.CreateTable[CompareCaps],
default: defaultTerm
]];
term.bestName ¬ bestName;
FOR names ¬ names, names.rest WHILE names # NIL DO
a: Alias ¬ NEW [AliasRep ¬ [names.first, term]];
term.names ¬ CONS[names.first, term.names];
tc.contents.Insert[a !OrderedSymbolTableRef.DuplicateKey => {
CONTINUE--can only collide with same term--}];
ENDLOOP;
Finally, parse capabilities
DO
capName: ROPE;
cap: Cap;
cancelIt: BOOL ¬ FALSE;
char: CHAR;
Ignore end-of-line?
IF from.PeekChar[] = '\\ THEN {
char: CHAR;
IF (char ¬ from.GetChar[]) # '\\ THEN ERROR;
IF NOT White[from.PeekChar[]] THEN Busted[];
[] ¬ from.SkipWhitespace[];
IF (char ¬ from.GetChar[]) # ': THEN Busted[];
LOOP;
};
IF White[from.PeekChar[]] THEN EXIT--done with caps--;
capName ¬ from.GetTokenRope[CapNameBuster].token;
IF capName.Length[] = 1 THEN Busted[];
cap ¬ NEW [CapRep ¬ [capName, NIL]];
char ¬ from.GetChar[];
IF char = '@ THEN {
cancelIt ¬ TRUE;
char ¬ from.GetChar[];
};
SELECT char FROM
': => cap.val ¬ NEW [BOOL ¬ TRUE];
'# => {
cap.val ¬ NEW [INT ¬ from.GetInt[!IO.Error => Busted[]]];
IF from.GetChar[] # ': THEN Busted[];
};
'= => cap.val ¬ ParseString[from];
ENDCASE => Busted[];
IF cancelIt THEN cap.val ¬ cancel;
IF cap.name.Equal["tc"] THEN {
defName: String ¬ NIL;
default: Term;
WITH cap.val SELECT FROM
s: String => defName ¬ s;
ENDCASE => defName ¬ NIL;
IF defName = NIL THEN Bitch["tc not a string"]
ELSE {
default ¬ defaultTerm;
IF defName.str.Length[] > 0 THEN default ¬ TCTerm[tc, defName.str]
ELSE {
i: INT ¬ Real.RoundLI[defName.pad];
IF i # 0 THEN {
name: ROPE ¬ Convert.RopeFromInt[i];
default ¬ TCTerm[tc, name]
};
};
term.default ¬ default
};
}
ELSE {
term.caps.Insert[cap !OrderedSymbolTableRef.DuplicateKey =>
CONTINUE --left value overrides right--];
};
ENDLOOP;
ENDLOOP;
};
TermNameBuster: PROC [char: CHAR] RETURNS [cc: IO.CharClass] --IO.BreakProc-- = {
cc ¬ SELECT char FROM
'|, ': => break,
ENDCASE => other};
CapNameBuster: PROC [char: CHAR] RETURNS [cc: IO.CharClass] --IO.BreakProc-- = {
cc ¬ SELECT char FROM
':, '#, '=, '@ => break,
IN [0C .. Ascii.SP] => sepr,
ENDCASE => other};
White: PROC [c: CHAR] RETURNS [white: BOOL] =
{white ¬ c IN [0C .. Ascii.SP]};
Numeric: PROC [c: CHAR] RETURNS [numeric: BOOL] =
{numeric ¬ (c IN ['0 .. '9]) OR (c = '.)};
ParseString: PROC [from: IO.STREAM] RETURNS [s: String] = {
padChars, strVal: ROPE ¬ NIL;
char: CHAR;
dotSeen, proportional: BOOL ¬ FALSE;
FOR char ¬ from.PeekChar[], from.PeekChar[] WHILE Numeric[char] DO
IF from.GetChar[] # char THEN ERROR;
IF char = '. THEN dotSeen ¬ TRUE;
padChars ¬ padChars.Cat[Rope.FromChar[char]];
ENDLOOP;
IF from.PeekChar[] = '* THEN {
IF from.GetChar[] # '* THEN ERROR;
proportional ¬ TRUE};
DO
char ¬ from.GetChar[];
IF char = ': THEN EXIT;
SELECT char FROM
'^ => {char ¬ from.GetChar[];
char ¬ Ascii.Control[char]};
'\\ => {char ¬ from.GetChar[];
SELECT char FROM
'E => char ¬ Ascii.ESC;
'n => char ¬ '\012;
'r => char ¬ '\015;
't => char ¬ '\t;
'b => char ¬ '\010;
'f => char ¬ '\014;
IN ['0 .. '7] => {
octChars: ROPE ¬ Rope.FromChar[char];
IF from.PeekChar[] IN ['0 .. '7] THEN {
octChars ¬ octChars.Concat[Rope.FromChar[from.GetChar[]]];
IF from.PeekChar[] IN ['0 .. '7] THEN {
octChars ¬ octChars.Concat[Rope.FromChar[from.GetChar[]]];
};
};
char ¬ '\000 + Convert.CardFromRope[octChars, 8];
};
'^, '\\ => char ¬ char;
ENDCASE => char ¬ char --really should Bitch, but UNIX is so sloppy, this saves a lot of headaches--;
};
ENDCASE;
strVal ¬ strVal.Cat[Rope.FromChar[char]];
ENDLOOP;
s ¬ NEW [StringRep ¬ [
pad: IF padChars = NIL THEN 0.0 ELSE IF dotSeen THEN Convert.RealFromRope[padChars] ELSE REAL[Convert.IntFromRope[padChars]],
proportional: proportional,
str: strVal]];
};
CompareCaps: PROC [r1, r2: REF ANY] RETURNS [c: Basics.Comparison] = {
Key: PROC [r: REF ANY] RETURNS [name: ROPE] = {
WITH r SELECT FROM
c: Cap => name ¬ c.name;
r: ROPE => name ¬ r;
ENDCASE => ERROR};
c ¬ Key[r1].Compare[Key[r2]];
};
CompareTerms: PROC [r1, r2: REF ANY] RETURNS [c: Basics.Comparison] = {
Key: PROC [r: REF ANY] RETURNS [name: ROPE] = {
WITH r SELECT FROM
a: Alias => name ¬ a.name;
r: ROPE => name ¬ r;
ENDCASE => ERROR};
c ¬ Key[r1].Compare[Key[r2]];
};
CompareTermCaps: PROC [r1, r2: REF ANY] RETURNS [c: Basics.Comparison] = {
Key: PROC [r: REF ANY] RETURNS [fi: FileID] = {
WITH r SELECT FROM
tc: TermCap => fi ¬ tc.fileID;
rfi: REF FileID => fi ¬ rfi­;
ENDCASE => ERROR};
fi1: FileID ¬ Key[r1];
fi2: FileID ¬ Key[r2];
c ¬ fi1.gName.Compare[fi2.gName, FALSE];
IF c = equal THEN c ¬ SELECT BasicTime.Period[from: fi2.create, to: fi1.create] FROM
<0 => less,
=0 => equal,
>0 => greater,
ENDCASE => ERROR;
};
AntiAlias: PROC [ra: REF ANY] RETURNS [t: Term] = {
IF ra = NIL THEN RETURN [NIL];
WITH ra SELECT FROM
a: Alias => RETURN [a.val];
ENDCASE => ERROR};
Add: PROC [name: ROPE, val: Val] = {
c: Cap¬ NEW [CapRep ¬ [name, val]];
defaultTerm.caps.Insert[c];
};
Start: PROC = {
termCaps ¬ OrderedSymbolTableRef.CreateTable[CompareTermCaps];
defaultTerm ¬ NEW [TermRep ¬ [
names: NIL,
caps: OrderedSymbolTableRef.CreateTable[CompareCaps]
]];
Add["cr", NEW [StringRep ¬ [str: "\015"]]];
Add["ff", NEW [StringRep ¬ [str: "\014"]]];
Add["nl", NEW [StringRep ¬ [str: "\012"]]];
Add["pc", NEW [StringRep ¬ [str: "\000"]]];
};
Start[];
}.