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, September 30, 1983 5:59 pm
DIRECTORY Atom, Ascii, FileIO, IO, RefText, Rope, UFFileManager, UFFontDirReader, UserTerminal;
UFFontDirReaderImpl: CEDAR PROGRAM
IMPORTS Atom, FileIO, IO, RefText, Rope, UFFileManager, UserTerminal
EXPORTS UFFontDirReader
= BEGIN OPEN UFFontDirReader;
EnumerateFontDirectory: PUBLIC PROCEDURE [fontDirectoryName: ROPE, examine: ExamineProc, result: ResultProc] = {
stream: IO.STREAM ← FileIO.Open[fontDirectoryName];
inputBuffer: REF TEXT ← RefText.ObtainScratch[128];
fontName: REF TEXT ← RefText.ObtainScratch[64];
codeScheme: REF TEXT ← RefText.ObtainScratch[64];
metricsName: REF TEXT ← RefText.ObtainScratch[64];
graphicsName: REF TEXT ← RefText.ObtainScratch[64];
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 ← FileIO.Open["UnifiedFonts.errorLog", append];
stream.PutF["%g Error at position %g in file %g", IO.time[], IO.int[locationOfBufferStart+tokenStart], IO.rope[fontDirectoryName]];
stream.Close;
TRUSTED {UserTerminal.BlinkDisplay[]};
};
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[inputBuffer, tokenLength];
};
AtomFromToken: PROC RETURNS [atom: ATOM] = {
Not called often; makes a atom with first char caps, rest lower case.
scratchText: REF TEXT ← RefText.ObtainScratch[64];
Save[scratchText];
scratchText[0] ← Rope.Upper[scratchText[0]];
FOR i: NAT IN [1..scratchText.length) DO
scratchText[i] ← Rope.Lower[scratchText[i]];
ENDLOOP;
atom ← Atom.MakeAtom[Rope.FromRefText[scratchText]];
RefText.ReleaseScratch[scratchText];
};
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] = {
r.length ← 0;
RefText.Append[to: r, from: inputBuffer, start: tokenStart, len: tokenLength];
};
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[]; Save[fontName]; GetToken[]};
Match["CODESCHEME:"] => {GetToken[]; Save[codeScheme]; GetToken[]};
Match["METRICS:"] => {GetToken[];
metricsType ←
SELECT TRUE FROM
Match["TFM"] => $Tfm,
Match["STRIKE"] => $Strike,
ENDCASE => AtomFromToken[];
GetToken[]; Save[metricsName]; GetToken[];
};
Match["GRAPHICS:"] => {GetToken[];
graphicsType ←
SELECT TRUE FROM
Match["PRESS"] => $Press,
Match["STRIKE"] => $Strike,
Match["SD"] => $Sd,
ENDCASE => AtomFromToken[];
GetToken[]; 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[inputBuffer];
RefText.ReleaseScratch[fontName];
RefText.ReleaseScratch[codeScheme];
RefText.ReleaseScratch[metricsName];
RefText.ReleaseScratch[graphicsName];
stream.Close[];
};
END.