DIRECTORY
ImageDefs: FROM "ImageDefs",
IODefs: FROM "IODefs",
PressDefs: FROM "PressDefs",
SegmentDefs: FROM "SegmentDefs",
StreamDefs: FROM "StreamDefs",
StringDefs: FROM "StringDefs",
SystemDefs: FROM "SystemDefs";

FontSampler: PROGRAM IMPORTS ImageDefs, IODefs, PressDefs, StreamDefs, StringDefs, SystemDefs =
BEGIN

Font:TYPE = POINTER TO FontBody;
FontBody:TYPE = RECORD[family:STRING, size:CARDINAL ← 0, face:CARDINAL ← 0,
rotation:CARDINAL ← 0, widths:Widths ← NIL];
Widths:TYPE = POINTER TO WidthBody;
WidthBody:TYPE = RECORD[micaX:ARRAY [0..256) OF INTEGER,
bBox:ARRAY [0..4) OF INTEGER];
JustificationMode: TYPE = {leftJustified, rightJustified, centered,
bottomJustified, topJustified};

labelFont, titleFont, commentFont: Font ← NIL;
wStream:StreamDefs.StreamHandle; --Fonts.Widths stream

p:PressDefs.PressFileDescriptor;
nullChar:CHARACTER = 0C;
str:STRING ← [15];
commandFileName: STRING ← [60];
pressFileName: STRING ← [60];

row,column:CARDINAL;
curX,curY:CARDINAL;
family:STRING ← [60];
size:CARDINAL ← 10;
face:CARDINAL←0;
rotation:CARDINAL←0;
magnification:CARDINAL←10;
keyWord:STRING ← [60];

leftEdge:CARDINAL←4000;
rightEdge:CARDINAL←19000;
bottomEdge:CARDINAL←6000;
topEdge:CARDINAL←24800;
tickLength:CARDINAL←125;
tickWidth:CARDINAL←7;
tickOffset:CARDINAL←125;
gridWidth:CARDINAL←20;
labelMargin:CARDINAL←200;
titleMargin:CARDINAL←700;
charsXOffset:CARDINAL←750;
charsYOffset:CARDINAL←450;
title:STRING ← [200];
comment1:STRING ← [200];
comment2:STRING ← [200];
comment3:STRING ← [200];

firstChar:CARDINAL←0B;
lastChar:CARDINAL←177B;
numCols:CARDINAL←8;
numRows:CARDINAL←16;

FindWidths: PROCEDURE[f:Font]=
BEGIN
success:BOOLEAN;
IF f=NIL THEN ERROR AttemptToFindWidthsOfNIL;
f.widths ← SystemDefs.AllocateHeapNode[SIZE[WidthBody]];
success ← PressDefs.LookupFontName[wStream, f.family, f.face, f.size,
f.rotation, @f.widths.micaX, NIL, @f.widths.bBox];
IF ~success THEN ERROR FontNotInWidthDictionary;
END;
FontNotInWidthDictionary: SIGNAL = CODE;
AttemptToFindWidthsOfNIL: SIGNAL = CODE;

PutString:
PROCEDURE[s:STRING,f:Font,x,y:CARDINAL,m:JustificationMode]=
BEGIN
length:CARDINAL ← 0;
height, i:CARDINAL;
IF f.widths=NIL THEN ERROR FontHasNoWidthData;
FOR i IN [0..s.length) DO
length ← length+f.widths.micaX[s[i]-0C];
ENDLOOP;
height ← f.widths.bBox[3]*8/10;
SELECT m FROM
leftJustified => BEGIN y ← y-height/2 END;
rightJustified => BEGIN y ← y-height/2; x ← x-length END;
centered => BEGIN y ← y-height/2; x ← x-length/2 END;
topJustified => BEGIN y ← y-height; x ← x-length/2 END;
bottomJustified => BEGIN x ← x-length/2 END;
ENDCASE;
PressDefs.SetFont[@p, f.family, f.size, f.face, f.rotation];
PressDefs.PutText[@p, s, x, y];
END;
FontHasNoWidthData:SIGNAL = CODE;

InitFont: PROCEDURE[fam:STRING, size:CARDINAL, face,rot:CARDINAL ← 0]
RETURNS [Font] =
BEGIN
f:Font;
f ← SystemDefs.AllocateHeapNode[SIZE[FontBody]];
f↑ ← FontBody[fam,size,face,rot,NIL];
RETURN [f];
END;

DefaultParameters:PROCEDURE =
BEGIN
leftEdge←4000;
rightEdge←19000;
bottomEdge←6000;
topEdge←24800;
tickLength←125;
tickWidth←7;
tickOffset←125;
gridWidth←20;

firstChar←0B;
lastChar←177B;
labelMargin←200;
titleMargin←700;
charsXOffset←750;
charsYOffset←450;
numCols←8;
numRows←16;

face←0;
rotation←0;
magnification←10;
END;

WriteFontSample:PROCEDURE =
BEGIN
--compute number of pages
firstRow:CARDINAL=firstChar/numCols;
lastRow:CARDINAL=lastChar/numCols;
totalRows:CARDINAL=lastRow-firstRow+1;
numPages:CARDINAL=(totalRows+numRows-1)/numRows;
page:CARDINAL;
--compute matrix dimensions
colWidth:CARDINAL=(rightEdge-leftEdge)/numCols;
rowHeight:CARDINAL=(topEdge-bottomEdge)/numRows;

FOR page IN [0..numPages)
DO
BEGIN
--output one page
thisNumRows:CARDINAL=IF page=numPages-1
THEN totalRows-(numPages-1)*numRows ELSE numRows;
thisFirstRow:CARDINAL=IF page=0 THEN firstRow
ELSE firstRow+page*numRows;
thisLastRow:CARDINAL=IF page=numPages-1 THEN lastRow
ELSE (firstRow+(page+1)*numRows)-1;
thisFirstChar:CARDINAL=IF page=0 THEN firstChar
ELSE numCols*thisFirstRow;
thisLastChar:CARDINAL=IF page=numPages-1 THEN lastChar
ELSE thisLastRow*numCols+numCols-1;
char:CARDINAL;

--Put down the rules of the grid;
FOR row IN [numRows-thisNumRows..numRows]
DO
PressDefs.PutRectangle[@p,leftEdge,bottomEdge+row*rowHeight,
numCols*colWidth+gridWidth,gridWidth]
ENDLOOP;
FOR column IN [0..numCols]
DO
PressDefs.PutRectangle[@p,leftEdge+column*colWidth,
bottomEdge+(numRows-thisNumRows)*rowHeight,
gridWidth,thisNumRows*rowHeight+gridWidth]
ENDLOOP;

--Put numeric labels on the grid, in labelFont;
FOR column IN [0..numCols)
DO
str.length←0;
StringDefs.AppendNumber[str,column,8];
PutString[str,labelFont,leftEdge+column*colWidth+colWidth/2,
bottomEdge+numRows*rowHeight+labelMargin,bottomJustified]
ENDLOOP;
FOR row IN [thisFirstRow..thisLastRow]
DO
str.length←0;
StringDefs.AppendChar[str,’#];
SELECT row*numCols FROM
IN [0B..7B] => StringDefs.AppendString[str,"00"];
IN [10B..77B] => StringDefs.AppendString[str,"0"];
ENDCASE;
StringDefs.AppendNumber[str,row*numCols,8];
PutString[str,labelFont,leftEdge-labelMargin,
bottomEdge+(numRows-row+thisFirstRow)*rowHeight-rowHeight/2,
rightJustified]
ENDLOOP;

--put title at the bottom of the page
PutString[title, titleFont, leftEdge+(numCols*colWidth/2),
bottomEdge-titleMargin, topJustified];
--and add comments below it
PutString[comment1,commentFont,leftEdge-1000,bottomEdge*6/10,leftJustified];
PutString[comment2,commentFont,leftEdge-1000,bottomEdge/2,leftJustified];
PutString[comment3,commentFont,leftEdge-1000,bottomEdge*4/10,leftJustified];

--put the characters and tick marks in place;
FOR char IN [thisFirstChar..thisLastChar]
DO
BEGIN
row←char/numCols;
column ← char MOD numCols;
curX←leftEdge+charsXOffset+column*colWidth;
curY←bottomEdge+charsYOffset+(numRows+thisFirstRow-row-1)*rowHeight;
PressDefs.PutRectangle[@p,curX-tickWidth/2,
curY-tickLength-tickOffset,tickWidth,tickLength];
PressDefs.PutRectangle[@p,curX-tickLength-tickOffset,
curY-tickWidth/2,tickLength,tickWidth];
str.length←0;
StringDefs.AppendChar[str,nullChar+char];
IF magnification#10 THEN
PressDefs.SetMagFont[@p,family,size,magnification,face,rotation]
ELSE PressDefs.SetFont[@p,family,size,face,rotation];
PressDefs.PutText[@p,str,curX,curY];
PressDefs.SetFont[@p,"TimesRoman",10];
PressDefs.SetSpaceX[@p,0-tickWidth/2];
PressDefs.SetSpaceY[@p,0-tickLength-tickOffset];
PressDefs.PutSpace[@p];
PressDefs.PutRectangleHere[@p,tickWidth,tickLength];
PressDefs.SetSpaceX[@p,tickOffset+tickWidth/2];
PressDefs.SetSpaceY[@p,tickLength+tickOffset-tickWidth/2];
PressDefs.PutSpace[@p];
PressDefs.PutRectangleHere[@p,tickLength,tickWidth];
PressDefs.ResetSpace[@p];
END
ENDLOOP;

PressDefs.WritePage[@p]
END;
ENDLOOP;
END; --of WriteFontSample

--set up default strings;
pressFileName.length←0;
StringDefs.AppendString[pressFileName,"sample.press"];
family.length←0;
StringDefs.AppendString[family,"TimesRoman"];
title.length←0;
StringDefs.AppendString[title,"titlestring"];
comment1.length←0;
StringDefs.AppendString[comment1,"first line of comment"];
comment2.length←0;
StringDefs.AppendString[comment2,"second line of comment"];
comment3.length←0;
StringDefs.AppendString[comment3,"third line of comment"];

wStream ← StreamDefs.NewWordStream["Fonts.Widths",
StreamDefs.Read];
labelFont ← InitFont["TimesRoman",10];
titleFont ← InitFont["TimesRoman",18,2];
commentFont ← InitFont["TimesRoman",10];

FindWidths[labelFont];
FindWidths[titleFont];
FindWidths[commentFont];

IODefs.WriteString["Command file name:"];
IODefs.ReadID[commandFileName];
IODefs.WriteLine[""];

IODefs.SetInputStream[StreamDefs.NewByteStream[
commandFileName,SegmentDefs.Read]];

--start parsing commands
DO
IODefs.WriteLine[""];
IODefs.ReadID[keyWord];
IODefs.WriteString[" "];
IF StringDefs.EquivalentString[keyWord,"OpenPressFile"] THEN
BEGIN
PressDefs.InitPressFileDescriptor[@p,pressFileName];
END
ELSE IF StringDefs.EquivalentString[keyWord,"ClosePressFile"] THEN
BEGIN
PressDefs.ClosePressFile[@p];
END
ELSE IF StringDefs.EquivalentString[keyWord,"pressFileName"] THEN
BEGIN
IODefs.ReadID[pressFileName];
END
ELSE IF StringDefs.EquivalentString[keyWord,"comment1"] THEN
BEGIN
IODefs.ReadLine[comment1];
END
ELSE IF StringDefs.EquivalentString[keyWord,"comment2"] THEN
BEGIN
IODefs.ReadLine[comment2];
END
ELSE IF StringDefs.EquivalentString[keyWord,"comment3"] THEN
BEGIN
IODefs.ReadLine[comment3];
END
ELSE IF StringDefs.EquivalentString[keyWord,"title"] THEN
BEGIN
IODefs.ReadLine[title];
END
ELSE IF StringDefs.EquivalentString[keyWord,"quit"] THEN
BEGIN
ImageDefs.StopMesa;
END
ELSE IF StringDefs.EquivalentString[keyWord,"reset"] THEN
BEGIN
DefaultParameters;
END
ELSE IF StringDefs.EquivalentString[keyWord,"tickLength"] THEN
BEGIN
tickLength←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"tickWidth"] THEN
BEGIN
tickWidth←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"tickOffset"] THEN
BEGIN
tickOffset←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"numRows"] THEN
BEGIN
numRows←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"numCols"] THEN
BEGIN
numCols←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"gridWidth"] THEN
BEGIN
gridWidth←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"firstChar"] THEN
BEGIN
firstChar←IODefs.ReadOctal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"lastChar"] THEN
BEGIN
lastChar←IODefs.ReadOctal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"charsXOffset"] THEN
BEGIN
charsXOffset←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"charsYOffset"] THEN
BEGIN
charsYOffset←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"leftEdge"] THEN
BEGIN
leftEdge←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"rightEdge"] THEN
BEGIN
rightEdge←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"bottomEdge"] THEN
BEGIN
bottomEdge←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"topEdge"] THEN
BEGIN
topEdge←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"family"] THEN
BEGIN
IODefs.ReadID[family];
END
ELSE IF StringDefs.EquivalentString[keyWord,"face"] THEN
BEGIN
face←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"TEXface"] THEN
BEGIN
size←IODefs.ReadDecimal[];
face←254-2*size;
END
ELSE IF StringDefs.EquivalentString[keyWord,"rotation"] THEN
BEGIN
rotation←60*IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"size"] THEN
BEGIN
size←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"magnification"] THEN
BEGIN
magnification←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"write"] THEN
BEGIN
--do the work
WriteFontSample;
END
ELSE IF StringDefs.EquivalentString[keyWord,"labelMargin"] THEN
BEGIN
labelMargin←IODefs.ReadDecimal[];
END
ELSE IF StringDefs.EquivalentString[keyWord,"titleMargin"] THEN
BEGIN
titleMargin←IODefs.ReadDecimal[];
END
ELSE
BEGIN
IODefs.WriteLine["Warning: Unrecognized keyword ignored."];
END;
ENDLOOP;

END.