UFFontDirReaderImpl.mesa
Written January 14, 1983 2:01 pm
Last edited by Michael Plass, July 22, 1983 12:00 pm
Last edited by Doug Wyatt, November 22, 1983 4:24 pm
DIRECTORY
Ascii USING [CR, LF, Lower, SP, TAB, Upper],
Atom USING [MakeAtom],
FS USING [StreamOpen],
IO USING [Close, PutF, int, time, rope, STREAM, GetBlock],
RefText USING [Append, ObtainScratch, ReleaseScratch],
Rope USING [FromRefText],
Terminal USING [BlinkBWDisplay, Current],
UFFileManager USING [KeyOfRefText],
UFFontDirReader;
UFFontDirReaderImpl: CEDAR PROGRAM
IMPORTS Ascii, Atom, FS, IO, RefText, Rope, Terminal, UFFileManager
EXPORTS UFFontDirReader
= BEGIN OPEN UFFontDirReader;
EnumerateFontDirectory: PUBLIC PROCEDURE [fontDirectoryName: ROPE, examine: ExamineProc, result: ResultProc] = {
stream: IO.STREAMFS.StreamOpen[fontDirectoryName];
inputBufferScratch: REF TEXT = RefText.ObtainScratch[128];
fontNameScratch: REF TEXT = RefText.ObtainScratch[64];
codeSchemeScratch: REF TEXT = RefText.ObtainScratch[64];
metricsNameScratch: REF TEXT = RefText.ObtainScratch[64];
graphicsNameScratch: REF TEXT = RefText.ObtainScratch[64];
inputBuffer: REF TEXT ← inputBufferScratch;
fontName: REF TEXT ← fontNameScratch;
codeScheme: REF TEXT ← codeSchemeScratch;
metricsName: REF TEXT ← metricsNameScratch;
graphicsName: REF TEXT ← graphicsNameScratch;
deviceType: DeviceType ← $Ideal;
metricsType: ATOM ← $Nil;
graphicsType: ATOM ← $Nil;
rotation: REAL ← 0;
size, plusSize, minusSize: REAL ← 0;
cp: NAT ← 0;
locationOfBufferStart: INT ← 0;
tokenStart, tokenLength: NAT ← 0;
Error: PROC = {
stream: IO.STREAM ← FS.StreamOpen["UnifiedFonts.errorLog", $append];
stream.PutF["%g Error at position %g in file %g", IO.time[], IO.int[locationOfBufferStart+tokenStart], IO.rope[fontDirectoryName]];
stream.Close;
Terminal.Current[].BlinkBWDisplay;
};
GetToken: PROC = {
Gets the next token into inputBuffer[tokenStart] .. inputBuffer[tokenLength-1]
c: CHAR;
tokenStart ← tokenStart+tokenLength;
tokenLength ← 0;
WHILE tokenStart<inputBuffer.length AND ((c ← inputBuffer[tokenStart]) = Ascii.SP OR c = Ascii.TAB OR c = Ascii.CR OR c = Ascii.LF OR c = ', OR c = ';) DO
tokenStart ← tokenStart + 1;
IF tokenStart = inputBuffer.length THEN RefillBuffer[];
ENDLOOP;
WHILE tokenStart+tokenLength<inputBuffer.length AND NOT ((c ← inputBuffer[tokenStart+tokenLength]) = Ascii.SP OR c = Ascii.TAB OR c = Ascii.CR OR c = Ascii.LF OR c = ', OR c = ';) DO
tokenLength ← tokenLength + 1;
IF tokenStart + tokenLength = inputBuffer.length THEN RefillBuffer[];
ENDLOOP;
};
RefillBuffer: PROC = {
FOR i: NAT IN [0..tokenLength) DO
inputBuffer[i] ← inputBuffer[i+tokenStart];
ENDLOOP;
inputBuffer.length ← tokenLength;
locationOfBufferStart ← locationOfBufferStart+tokenStart;
tokenStart ← 0;
[] ← stream.GetBlock[block: inputBuffer, startIndex: tokenLength, count: inputBuffer.maxLength-tokenLength];
};
Match: PROC [key: REF READONLY TEXT] RETURNS [equal: BOOLEAN] = {
i: NAT ← tokenStart;
IF key.length # tokenLength THEN RETURN [FALSE];
FOR j: NAT IN [0..key.length) DO
IF key[j]#inputBuffer[i] THEN RETURN [FALSE];
i←i+1;
ENDLOOP;
RETURN [TRUE]
};
GetDimn: PROC [] RETURNS [dimn: REAL] = {
dimn ← TokenAsReal[];
GetToken[];
SELECT TRUE FROM
Match["mm"] => {GetToken[]; dimn ← dimn*72/25.4};
Match["cm"] => {GetToken[]; dimn ← dimn*72/2.54};
Match["in"] => {GetToken[]; dimn ← dimn*72};
Match["bp"] => {GetToken[]};
Match["pt"] => {GetToken[]; dimn ← dimn*72/72.27};
ENDCASE => NULL;
};
TokenAsReal: PROC [] RETURNS [real: REAL] = {
c: CHAR ← ' ;
i: NAT ← tokenStart;
num: REAL ← 0;
denom: REAL ← 1;
WHILE i < inputBuffer.length AND (c ← inputBuffer[i]) IN ['0..'9] DO
num ← 10.0*num + (c-'0);
i ← i+1;
ENDLOOP;
IF c='. THEN {i ← i+1; c ← ' ;
WHILE i < inputBuffer.length AND (c ← inputBuffer[i]) IN ['0..'9] DO
num ← 10.0*num + (c-'0);
denom ← 10.0*denom;
i ← i+1;
ENDLOOP;
}
ELSE IF c='/ THEN {i ← i+1; denom ← 0;
WHILE i < inputBuffer.length AND (c ← inputBuffer[i]) IN ['0..'9] DO
denom ← 10.0*denom + (c-'0);
i ← i+1;
ENDLOOP;
};
tokenLength ← i-tokenStart;
IF denom=0.0 THEN {Error[]; denom𡤁};
IF tokenLength=0 THEN Error[];
real ← num/denom;
};
Save: PROC[r: REF TEXT] RETURNS[REF TEXT] = {
r.length ← 0;
RETURN[RefText.Append[to: r, from: inputBuffer, start: tokenStart, len: tokenLength]];
};
AtomFromToken: PROC RETURNS [atom: ATOM] = {
Not called often; makes an atom with first char upper case, rest lower case.
scratch: REF TEXT = RefText.ObtainScratch[64];
text: REF TEXT ← Save[scratch];
text[0] ← Ascii.Upper[text[0]];
FOR i: NAT IN [1..text.length) DO
text[i] ← Ascii.Lower[text[i]];
ENDLOOP;
atom ← Atom.MakeAtom[Rope.FromRefText[text]];
RefText.ReleaseScratch[scratch];
};
RefillBuffer[];
GetToken[];
WHILE tokenLength>0 DO
SELECT TRUE FROM
Match["DEVICE:"] => {GetToken[];
SELECT TRUE FROM
Match["Ideal"] => deviceType ← $Ideal;
Match["Spruce"] => deviceType ← $Spruce;
Match["Press"] => deviceType ← $Press;
Match["Ideal"] => deviceType ← $Screen;
ENDCASE => deviceType ← AtomFromToken[];
GetToken[]
};
Match["SIZE:"] => {GetToken[];
IF Match["ANY"] THEN {GetToken[]; size ← minusSize ← 0; plusSize ← 1000000.0}
ELSE {
size ← plusSize ← minusSize ← GetDimn[];
DO SELECT TRUE FROM
Match["+"] => {GetToken[]; plusSize ← size + GetDimn[]};
Match["-"] => {GetToken[]; minusSize ← size - GetDimn[]};
Match["+-"] => {r: REAL; GetToken[]; r ← GetDimn[]; plusSize ← size + r; minusSize ← size - r};
ENDCASE => EXIT;
ENDLOOP;
};
};
Match["ROTATION:"] => {GetToken[];
IF Match["ANY"] THEN rotation ← -360.0 ELSE rotation ← TokenAsReal[];
GetToken[]
};
Match["FONTNAME:"] => {GetToken[]; fontName ← Save[fontName]; GetToken[]};
Match["CODESCHEME:"] => {GetToken[]; codeScheme ← Save[codeScheme]; GetToken[]};
Match["METRICS:"] => {GetToken[];
metricsType ←
SELECT TRUE FROM
Match["TFM"] => $Tfm,
Match["STRIKE"] => $Strike,
ENDCASE => AtomFromToken[];
GetToken[]; metricsName ← Save[metricsName]; GetToken[];
};
Match["GRAPHICS:"] => {GetToken[];
graphicsType ←
SELECT TRUE FROM
Match["PRESS"] => $Press,
Match["STRIKE"] => $Strike,
Match["SD"] => $Sd,
ENDCASE => AtomFromToken[];
GetToken[]; graphicsName ← Save[graphicsName]; GetToken[];
};
Match["DEFINEFONT"] => {
GetToken[];
IF examine[
candidateFontName: fontName,
candidateSize: size,
candidateMaxSize: plusSize,
candidateMinSize: minusSize,
candidateRotation: rotation,
candidateDeviceType: deviceType
]
THEN {
quit: BOOLEAN ← result[
candidateFontName: fontName,
candidateSize: size,
candidateMaxSize: plusSize,
candidateMinSize: minusSize,
candidateRotation: rotation,
candidateDeviceType: deviceType,
metricsType: metricsType,
codeScheme: UFFileManager.KeyOfRefText[codeScheme],
metricsName: UFFileManager.KeyOfRefText[metricsName],
graphicsType: graphicsType,
graphicsName: UFFileManager.KeyOfRefText[graphicsName]
];
IF quit THEN EXIT;
};
};
ENDCASE => {Error[]; EXIT};
ENDLOOP;
RefText.ReleaseScratch[inputBufferScratch];
RefText.ReleaseScratch[fontNameScratch];
RefText.ReleaseScratch[codeSchemeScratch];
RefText.ReleaseScratch[metricsNameScratch];
RefText.ReleaseScratch[graphicsNameScratch];
stream.Close[];
};
END.