LandPrintDirB.mesa;
Last Edited by: Sweet, September 15, 1985 2:40:27 pm PDT
DIRECTORY
Ascii,
Buttons,
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, Container, Create],
Convert,
FS,
IO,
LandPrintDefs,
MessageWindow,
RefText,
Rope,
Rules USING [Create, Rule],
SafeStorage,
SirPress,
TSFont,
TSTypes,
ViewerClasses USING [Viewer, ViewerClassRec],
ViewerOps USING [PaintViewer],
ViewerTools USING [GetContents];
LandPrintDirB: CEDAR PROGRAM    
IMPORTS Commander, Containers, Convert, FS, IO, LandPrintDefs, MessageWindow, RefText, Rope, Rules, SafeStorage, SirPress, TSFont, TSTypes, ViewerOps, ViewerTools
EXPORTS LandPrintDefs =
BEGIN OPEN LandPrintDefs;
The Containers interface is used to create an outer envelope or "container" for the different sections below. For uniformity, we define some standard distances between entries in the tool.
entryHeight: CARDINAL = 15; -- how tall to make each line of items
entryVSpace: CARDINAL = 8;  -- vertical leading space between lines
entryHSpace: CARDINAL = 10;  -- horizontal space between items in a line
dash: CHAR = Ascii.ControlV;
frontMatterPages: CARDINAL ← 2;
PromptRec: TYPE = RECORD [
handle: Handle, viewer: ViewerClasses.Viewer ← NIL];
PromptHandle: TYPE = REF PromptRec;
MakeTool: Commander.CommandProc = BEGIN
rule: Rules.Rule;
my: Handle ← NEW[MyRec];
my.outer ← Containers.Create[[-- construct the outer container
name: "Landscape Directory Printer", -- name displayed in the caption
iconic: TRUE,   -- so tool will be iconic (small) when first created
column: left,    -- initially in the left column
scrollable: FALSE ]];  -- inhibit user from scrolling contents
MakeCommands[my];  -- build each (sub)viewer in turn
rule ← Rules.Create [[parent: my.outer, wy: my.height, ww: my.outer.cw, wh: 2]];
Containers.ChildXBound[my.outer, rule];
my.height ← my.height + entryHeight + 2; -- interline spacing
MakeTypescript[my];
ViewerOps.PaintViewer[my.outer, all];    -- reflect above change
END;
DoIt: PUBLIC Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = BEGIN
force the selection into the user input field
handle: Handle ← NARROW[clientData]; -- get our data
BEGIN
ENABLE {
UNWIND => {IF handle.in # NIL THEN handle.in.Close[]; handle.in ← NIL};
Problem, ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}};
fName: ROPE = ViewerTools.GetContents[handle.cmd.inputFile];
pName: ROPE = ViewerTools.GetContents[handle.cmd.pressFile];
nSheets: CARDINAL;
Val: PROC [v: ViewerClasses.Viewer, default: INT] RETURNS [n: INT] = {
n ← Convert.IntFromRope[ViewerTools.GetContents[v] !
SafeStorage.NarrowFault => {n ← default; GO TO gub};
Convert.Error => {
MessageWindow.Append[message: "invalid number", clearFirst: TRUE];
n ← default; GO TO gub};
];
EXITS
gub => NULL;
};
IF fName = NIL OR pName = NIL THEN {
handle.tsOut.Put[[rope["specify input file name"]], [character['\n]]];
RETURN};
handle.in ← OpenFile[fName];
IF handle.in # NIL THEN handle.eof ← FALSE; handle.pageNumber ← 1;
IF pName # NIL AND Rope.Length[pName] # 0 THEN {
nameAddr, fumcWidth: INT;
handle.out ← FS.StreamOpen[fileName: pName, accessOptions: $create];
handle.press ← SirPress.Create[outputStream: handle.out, fileNameForHeaderPage: pName];
handle.dim.yLead ← Val[handle.cmd.yLead, 8];
handle.dim.fontSize ← Val[handle.cmd.fontSize, 10];
handle.dim.lineHeight ← Val[handle.cmd.lineHeight, 12];
handle.dim.pageWidth ← Val[handle.cmd.pageWidth, 612];
handle.dim.pageHeight ← Val[handle.cmd.pageHeight, 792];
handle.dim.topMargin ← Val[handle.cmd.topMargin, 72];
handle.dim.bottomMargin ← Val[handle.cmd.bottomMargin, 60];
handle.dim.leftMargin ← Val[handle.cmd.leftMargin, 54];
handle.dim.rightMargin ← Val[handle.cmd.rightMargin, 72];
handle.dim.fudgePoints ← Val[handle.cmd.fudgePoints, 6];
handle.dim.displayHeight ← Val[handle.cmd.displayHeight, 18];
handle.dim.tabHeight ← Val[handle.cmd.tabHeight, 8];
handle.dim.nameIndent ← Val[handle.cmd.nameIndent, 18];
handle.press.SetPageSize[110, 85];
LookupFonts[handle];
handle.yTop ← handle.dim.pageHeight - handle.dim.topMargin;
handle.phoneX ← handle.dim.leftMargin;
handle.phoneX2 ← handle.phoneX + PWidth[handle, "(415) ", body];
handle.nameX ← handle.phoneX + PWidth[handle, "(415) 321-9039", body] + 12;
handle.zipX ← handle.dim.pageWidth - handle.dim.rightMargin - PWidth[handle, "94303", body];
handle.townX ← handle.zipX - PWidth[handle, "EPA", body] - 9;
nameAddr ← handle.townX - handle.nameX;
handle.addrX ← handle.nameX;
handle.addrPWidth ← handle.townX - handle.addrX;
fumcWidth ←
PWidth[handle, "FUMPA", headingLarge] +
PWidth[handle, "IRST NITED ETHODIST, ALO LTO", headingSmall];
handle.fumcX ← RightX[handle, fumcWidth];
handle.prevInitial ← 0C;
handle.prevZip ← NIL;
handle.firstOnPage ← NIL; handle.affiliateThisPage ← FALSE;
handle.entry ← NEW[EntrySeqBody[1000]];
handle.page ← NEW[PageDataSeqBody[100]];
FOR j: CARDINAL IN [0..100) DO
handle.page[j] ← [];
ENDLOOP;
handle.page.count ← frontMatterPages; -- for front matter
handle.page[frontMatterPages] ← [start: 0, number: 1];
handle.reallyPrinting ← FALSE;
}
ELSE Quit[handle, "No output file"];
handle.tsOut.PutText["Reading:"];
WHILE ~handle.eof DO
InputEntry[handle];
ENDLOOP;
IF handle.firstOnPage # NIL THEN {
handle.entry.count ← handle.entry.count + 1;
FinishPage[handle]};
handle.reallyPrinting ← TRUE;
handle.pageParity ← 0;
handle.pageLoc ← R90T;
handle.tsOut.PutText["Printing:"];
PrintCover[handle];
IF handle.perfectBind^ THEN {
FOR k: CARDINAL IN [0..handle.page.count) DO
ReprintPage[handle, k];
ReprintPage[handle, k];
ENDLOOP;
}
ELSE {
nSheets ← (handle.page.count +3)/4;
FOR k: CARDINAL IN [0..nSheets) DO
ReprintPage[handle, 2*k];
ReprintPage[handle, 4*nSheets - 2*k -1];
ReprintPage[handle, 2*k + 1];
ReprintPage[handle, 4*nSheets - 2*k -2];
ENDLOOP;
};
handle.press.ClosePress[]; handle.press ← NIL;
EXITS
done => NULL;
END; -- of Enable
IF handle.in # NIL THEN handle.in.Close[];
IF handle.out # NIL THEN handle.out.Close[];
handle.tsOut.Put[[character['\n]], [rope["done"]], [character['\n]]];
handle.entry ← NIL;
handle.page ← NIL;
END;
PrintCover: PROC [h: Handle] = {
PT: PROC [t: ROPE, x, y: INT] = {PrintText[h, t, x, y]};
PTH: PROC [t: ROPE, f: FontClass] = {SetFont[h, f]; PrintHere[h, t]};
SF: PROC [class: FontClass] = {SetFont[h, class]};
y: INT ← h.dim.pageHeight - h.dim.topMargin - h.dim.displayHeight;
CenterText[h, y, "MEMBERSHIP DIRECTORY", display];
y ← y - 2*h.dim.lineHeight;
CenterText[h, y, "September 15, 1985", display];
y ← h.dim.bottomMargin + 7 * h.dim.lineHeight;
CenterText[h, y, "First United Methodist Church", display];
y ← y - 2*h.dim.lineHeight;
CenterText[h, y, "625 Hamilton Avenue at Webster", display];
y ← y - 2*h.dim.lineHeight;
CenterText[h, y, "Palo Alto, California 94301", display];
y ← y - 2*h.dim.lineHeight;
CenterText[h, y, "Telephone: (415) 323-6167", display];
h.press.WritePage[]};
PrintFrontMatter: PROC [h: Handle, number: CARDINAL] = {
PT: PROC [t: ROPE, x, y: INT] = {PrintText[h, t, x, y]};
PTH: PROC [t: ROPE, f: FontClass] = {SetFont[h, f]; PrintHere[h, t]};
SF: PROC [class: FontClass] = {SetFont[h, class]};
y: INT ← h.dim.pageHeight - h.dim.topMargin - h.dim.displayHeight;
w, x: INT;
LabeledName: PROC [label, name: ROPE, bold: BOOLTRUE] = {
SF[IF bold THEN bodyBold ELSE title];
PT[label, x, y];
PTH[" \030 ", title];
PTH[name, title];
y ← y - (3*h.dim.lineHeight)/2;
};
TownAbbr: PROC [abbr, name: ROPE] = {
PT[abbr, x, y];
PT[name, x+30, y];
y ← y - h.dim.lineHeight;
};
SELECT number FROM
0 => {
CenterText[h, y, "First United Methodist Church", display];
y ← y - 2*h.dim.lineHeight;
CenterText[h, y, "625 Hamilton Avenue Palo Alto, California 94301", bodyBold];
y ← y - h.dim.lineHeight;
CenterText[h, y, "Telephone: (415) 323-6167", bodyBold];
y ← y - 3*h.dim.lineHeight;
CenterText[h, y, "Office Hours: 9:00-5:00 Monday through Friday", bodyBold];
y ← y - 3*h.dim.lineHeight;
CenterText[h, y, "Church Staff", display];
y ← y - 2*h.dim.lineHeight;
x ← CenterX[h, PWidth[h, "Office Hours: 9:00-5:00 Monday through Friday", bodyBold]];
SF[bodyBold];
PT["Ministers", x, y];
PTH[" \030 ", title];
w ← PWidth[h, "Ministers", bodyBold] + PWidth[h, " \030 ", title];
PT["Douglas I. Norris", x+w, y];
y ← y - h.dim.lineHeight;
PT["Glenn S. Fuller", x+w, y];
y ← y - (3*h.dim.lineHeight)/2;
LabeledName["Church Business Administrator", "Florence T. Wegner"];
SF[bodyBold];
PT["Secretaries", x, y];
PTH[" \030 ", title];
w ← PWidth[h, "Secretaries", bodyBold] + PWidth[h, " \030 ", title];
PT["Finance: Ruth Willard", x+w, y];
y ← y - h.dim.lineHeight;
PT["Ministers: Joanne Perry", x+w, y];
y ← y - h.dim.lineHeight;
PT["Communications: Cathy Floyd", x+w, y];
y ← y - (3*h.dim.lineHeight)/2;
LabeledName["Director of Children's Ministry", "Dorothy Power"];
LabeledName["Director of Youth Ministry", "Neli Moody-Berne"];
LabeledName["Director of Music", "Leroy Kromm"];
LabeledName["Organist", "Steven Gray"];
SF[bodyBold];
PT["Choir Directors", x, y];
y ← y - (3*h.dim.lineHeight)/2;
x ← x + 18;
LabeledName["Chancel Choir", "Leroy Kromm", FALSE];
LabeledName["Youth and Adult Choirs", "Leroy Kromm", FALSE];
LabeledName["Children's Choirs", "Linda Jordan", FALSE];
LabeledName["Handbell Choirs", "Sara Salsbury", FALSE];
x ← x - 18;
LabeledName["Custodian", "Brian Neeley"];
LabeledName["Librarian", "Virginia Williams"];
LabeledName["Membership Secretary", "Barbara Busby"];
y ← y - (3*h.dim.lineHeight)/2;
CenterText[h, y, "Education building pay phone: (415) 853-8801", bodyBold];
y ← y - (3*h.dim.lineHeight)/2;
CenterText[h, y, "Sanctuary pay phone: (415) 853-8843", bodyBold];
};
1 => {
y ← h.dim.bottomMargin + 15 * h.dim.lineHeight;
x ← 72;
SF[body];
PT["This Directory includes the names of those persons on the church", x, y];
y ← y - h.dim.lineHeight;
PT["roll as of September 15, 1985. Non-member spouses and children", x, y];
y ← y - h.dim.lineHeight;
PT["not yet confirmed in membership are shown in ", x, y]; PTH["italics.", smallItalic];
SF[body];
y ← y - 2*h.dim.lineHeight;
PT["Cities are indicated as follows:", x, y];
y ← y - 2*h.dim.lineHeight;
y ← h.dim.bottomMargin + 9 * h.dim.lineHeight;
TownAbbr["A", "Atherton"];
TownAbbr["C", "Cupertino"];
TownAbbr["EPA", "East Palo Alto"];
TownAbbr["LA", "Los Altos"];
TownAbbr["LAH", "Los Altos Hills"];
TownAbbr["MP", "Menlo Park"];
TownAbbr["MV", "Mountain View"];
TownAbbr["PA", "Palo Alto"];
TownAbbr["PV", "Portola Valley"];
y ← h.dim.bottomMargin + 9 * h.dim.lineHeight;
x ← 3*72;
TownAbbr["RC", "Redwood City"];
TownAbbr["S", "Stanford"];
TownAbbr["Svl", "Sunnyvale"];
TownAbbr["SC", "Santa Clara"];
TownAbbr["SF", "San Francisco"];
TownAbbr["SJ", "San Jose"];
TownAbbr["SM", "San Mateo"];
TownAbbr["W", "Woodside"];
};
ENDCASE;
NewPage[h]};
CenterText: PROC [h: Handle, y: INT, t: ROPE, f: FontClass] = {
SetFont[h, f];
PrintText[h, t, CenterX[h, PWidth[h, t, f]], y]};
CenterX: PROC [h: Handle, w: INT] RETURNS [x: INT] = {
RETURN[ h.dim.leftMargin + (h.dim.pageWidth - h.dim.leftMargin - h.dim.rightMargin - w)/2]};
RightX: PROC [h: Handle, w: INT] RETURNS [x: INT] = {
RETURN[h.dim.pageWidth - h.dim.rightMargin - w]};
PWidth: PROC [h: Handle, s: ROPE, class: FontClass] RETURNS [INT] = {
w: TSTypes.Dimn ← [0];
ref: TSFont.Ref ← h.fontInfo[class];
IF ref = NIL THEN RETURN [0];
FOR i: INT IN [0..Rope.Length[s]) DO
w ← [w + TSFont.Width[ref, Rope.Fetch[s, i]]];
ENDLOOP;
RETURN [TSTypes.DimnInt[w, TSTypes.pt]];
};
UC: PROC [c: CHAR] RETURNS [CHAR] = {
RETURN[IF c IN ['a..'z] THEN VAL[c.ORD - ORD['a] + ORD['A]] ELSE c]};
CFName: PROC [h: Handle, name: ROPE] RETURNS [cf: ROPE] = {
funny: BOOLEANFALSE;
lastName: REF TEXTNEW[TEXT[Rope.Length[name]]]; -- plenty long
FOR i: INT IN [0..Rope.Length[name]) DO
c: CHARUC[Rope.Fetch[name, i]];
SELECT c FROM
', => EXIT;
'*, '+ => LOOP;
ENDCASE => {
IF c = ' AND ~funny THEN {
funny ← TRUE; h.tsOut.Put[[character['\n]], [rope[name]], [character['\n]]]};
lastName[lastName.length] ← c; lastName.length ← lastName.length + 1};
ENDLOOP;
RETURN[Rope.FromRefText[lastName]]};
PressNames: PROC [h: Handle, name: ARRAY [0..5) OF ROPE] = {
ascent: INT = h.dim.fontSize;
PT: PROC [t: ROPE, x, y: INT] = {PrintText[h, t, x, y]};
PTH: PROC [t: ROPE, f: FontClass] = {SetFont[h, f]; PrintHere[h, t]};
SF: PROC [class: FontClass] = {SetFont[h, class]};
NameBreak: IO.BreakProc = {
RETURN [SELECT char FROM
'&, ', => break,
'\t => sepr, -- blanks are allowed in names
ENDCASE => other]};
default: FontClass ← bodyBold;
ns: STREAMNIL;
GetName: PROC RETURNS [r: ROPE, cl: FontClass, affiliate: BOOLEAN, brk: CHAR] = {
cl ← default; affiliate ← FALSE;
[] ← ns.SkipWhitespace[];
IF ns.EndOf[] THEN RETURN [NIL, cl, FALSE, 0C];
SELECT ns.PeekChar[] FROM
'+ => {h.affiliateThisPage ← affiliate ← TRUE; [] ← ns.GetChar[]};
'* => {cl ← bodyItalic; [] ← ns.GetChar[]};
ENDCASE;
r ← GetTokenRope[ns, NameBreak].token;
IF ns.EndOf[] THEN brk ← 0C ELSE brk ← ns.GetChar[]};
t: ROPE; bk: CHAR;
affiliate: BOOLEAN;
fc: FontClass;
ns ← IO.RIS[name[0]];
[t, default, affiliate, bk] ← GetName[]; -- last name
IF affiliate THEN {
SF[symbols]; PT[t: "!", x: h.nameX - PWidth[h, "!", symbols], y: h.yTop - ascent]};
SF[default];
PT[t: t, x: h.nameX, y: h.yTop - ascent];
PTH[", ", default];
DO
[t, fc, affiliate, bk] ← GetName[];
IF t = NIL THEN EXIT;
IF affiliate THEN PTH["!", symbols];
PTH[t, fc];
SELECT bk FROM
'& => PTH["& ", default];
', => PTH[", ", default];
ENDCASE;
ENDLOOP;
do I have to close ns?
FOR i: CARDINAL IN [1..nLines) WHILE name[i] # NIL DO
y: INT = h.yTop - i*h.dim.lineHeight - ascent;
x: INTMAX[h.nameX + h.dim.nameIndent, h.phoneLast[i] + 12];
ns ← IO.RIS[name[i], ns];
[t, fc, affiliate, bk] ← GetName[];
IF t = NIL THEN LOOP;
IF affiliate THEN {
SF[symbols]; PT[t: "!", x: h.nameX + h.dim.nameIndent - PWidth[h, "!", symbols], y: y]};
SF[fc];
PT[t: t, x: x, y: h.yTop - i*h.dim.lineHeight - ascent];
DO
SELECT bk FROM
'& => PTH["& ", default];
', => PTH[", ", default];
ENDCASE;
[t, fc, affiliate, bk] ← GetName[];
IF t = NIL THEN EXIT;
IF affiliate THEN PTH["!", symbols];
PTH[t, fc];
ENDLOOP;
ENDLOOP;
};
PressPhone: PROC [h: Handle, phone: ARRAY [0..5) OF ROPE] = {
ascent: INT = h.dim.fontSize;
number: ROPE;
SF: PROC [class: FontClass] = {SetFont[h, class]};
PT: PROC [t: ROPE, x, y: INT] = {PrintText[h, t, x, y]};
PTH: PROC [t: ROPE, f: FontClass] = {SetFont[h, f];PrintHere[h, t]};
h.phoneLast ← ALL[0];
FOR i: INT IN SmallCount WHILE phone[i] # NIL DO
p: ROPE = phone[i];
y: INT = h.yTop - i*h.dim.lineHeight - ascent;
x: INT ← h.phoneX;
first: INT ← 0;
len: INT = Rope.Length[p];
last: INT ← len;
work: BOOLEANFALSE;
IF UC[Rope.Fetch[p, 0]] = 'W THEN {work ← TRUE; first ← 1};
IF len > 6 THEN FOR j: INT IN [6..len) DO
IF Rope.Fetch[p, j] = '( THEN {last ← j; EXIT};
ENDLOOP;
IF Rope.Length[p] > first+6 AND Rope.Equal[Rope.Substr[p, first, 6], "(415) "] THEN {
x ← h.phoneX2; first ← first + 6};
IF UC[Rope.Fetch[p, first]] = 'X THEN x ← h.phoneX2 + 12;
IF work THEN {
SF[bodyItalic]; PT[t: "w", x: x-PWidth[h, "w", bodyItalic]-2, y: y]};
number ← Rope.Substr[p, first, last - first];
SF[body]; PT[t: number, x: x, y: y];
h.phoneLast[i] ← x + PWidth[h, number, body];
IF last < len THEN {
name: ROPE = Rope.Substr[p, last, len - last];
PTH[t: name, f: tiny];
h.phoneLast[i] ← h.phoneLast[i] + PWidth[h, name, tiny]};
ENDLOOP};
PressEntry: PROC [h: Handle, e: Entry] = {
ascent: INT = h.dim.fontSize;
lastName: ROPE;
eLines: CARDINAL ← 1;
pLines, aLines, nLines: CARDINAL ← 0;
addLine, tLine, zLine: CARDINAL ← 0;
newLetter: BOOLEANFALSE;
PT: PROC [t: ROPE, x, y: INT] = {PrintText[h, t, x, y]};
x, eh, eh2: INT;
myFirst: CHAR;
ez: ROPEIF e.zip = NIL THEN "" ELSE e.zip;
FOR i: CARDINAL DECREASING IN SmallCount DO
IF e.phone[i] # NIL THEN {pLines ← i+1; EXIT};
ENDLOOP;
FOR i: CARDINAL DECREASING IN SmallCount DO
IF e.name[i] # NIL THEN {
addLine ← nLines ← i+1; tLine ← addLine; EXIT};
ENDLOOP;
FOR i: CARDINAL DECREASING IN SmallCount DO
IF e.addr [i] # NIL THEN {aLines ← i+1; EXIT};
ENDLOOP;
eLines ← MAX[pLines, nLines + aLines];
IF e.town # NIL THEN {
tLine ← addLine;
WHILE PWidth[h, e.addr[tLine], body] > h.addrPWidth DO
IF tLine = nLines-1 THEN Quit[h, "no room for town"];
tLine ← tLine + 1;
ENDLOOP;
zLine ← tLine}
ELSE {
tLine ← 0;
FOR i: CARDINAL DECREASING IN SmallCount DO
IF e.addr[i] # NIL THEN {zLine ← i + addLine; EXIT};
ENDLOOP;
};
eLines ← MAX[eLines, tLine+1, zLine+1];
eh ← eLines * h.dim.lineHeight;
lastName ← CFName[h, e.name[0]];
myFirst ← Rope.Fetch[lastName, 0];
newLetter ← SELECT TRUE FROM
h.alphaSort^ => h.prevInitial # myFirst,
ENDCASE => FALSE;
IF newLetter THEN eh2 ← eh + 2*h.dim.displayHeight
ELSE eh2 ← eh;
IF h.yTop - eh2 < h.dim.bottomMargin THEN FinishPage[h];
IF newLetter THEN {
l: ROPE = Rope.FromChar[myFirst];
h.yTop ← h.yTop - h.dim.displayHeight;
SetFont[h, display];
PT[t: l, x: CenterX[h, PWidth[h, l, display]], y: h.yTop];
h.tsOut.PutChar[myFirst];
h.yTop ← h.yTop - h.dim.displayHeight;
h.prevInitial ← myFirst;
h.prevZip ← ez};
SetFont[h, body];
PressPhone[h, e.phone];
PressNames[h, e.name];
SetFont[h, body];
x ← h.addrX;
FOR i: CARDINAL IN SmallCount DO
IF e.addr[i] = NIL THEN EXIT;
PT[t: e.addr[i], x: x, y: h.yTop - (addLine + i)*h.dim.lineHeight - ascent];
ENDLOOP;
IF e.town # NIL THEN
PT[t: e.town, x: h.townX, y: h.yTop - tLine*h.dim.lineHeight - ascent];
IF e.zip # NIL THEN
PT[t: e.zip, x: h.zipX, y: h.yTop - zLine*h.dim.lineHeight - ascent];
h.yTop ← h.yTop - eh - h.dim.yLead;
h.lastOnPage ← lastName;
IF h.firstOnPage = NIL THEN h.firstOnPage ← lastName;
};
FinishPage: PROC [h: Handle] = {
names, pageText: ROPE;
nx, hy: INT;
PT: PROC [t: ROPE, x, y: INT] = {PrintText[h, t, x, y]};
PTH: PROC [t: ROPE, f: FontClass] = {SetFont[h, f]; PrintHere[h, t]};
SF: PROC [class: FontClass] = {SetFont[h, class]};
Rectangle[h: h,
xstart: h.dim.leftMargin, ystart: h.dim.pageHeight - h.dim.topMargin + h.dim.lineHeight,
xlen: h.dim.pageWidth - h.dim.leftMargin - h.dim.rightMargin, ylen: 1];
names ← IF Rope.Equal[h.firstOnPage, h.lastOnPage] THEN h.firstOnPage
ELSE Rope.Cat[h.firstOnPage, Rope.FromChar[dash], h.lastOnPage];
hy ← h.dim.pageHeight - h.dim.topMargin + 2*h.dim.lineHeight;
IF ~h.duplex^ OR (h.pageNumber MOD 2 = 1) THEN {
nx ← RightX[h, PWidth[h, names, tabs]];
PT[t: "Fall 1985", x: h.dim.leftMargin, y: hy];
}
ELSE {
nx ← h.dim.leftMargin;
SF[headingLarge];
PT[t: "F", x: h.fumcX, y: hy];
PTH["IRST ", headingSmall];
PTH["U", headingLarge];
PTH["NITED ", headingSmall];
PTH["M", headingLarge];
PTH["ETHODIST, ", headingSmall];
PTH["P", headingLarge];
PTH["ALO ", headingSmall];
PTH["A", headingLarge];
PTH["LTO", headingSmall];
SF[date];
};
SF[tabs];
PT[t: names, x: nx, y: hy];
pageText ← Convert.RopeFromInt[h.pageNumber];
nx ← CenterX[h, PWidth[h, pageText, pageNum]];
SF[pageNum];
PT[t: pageText, x: nx, y: h.dim.bottomMargin - 3*h.dim.lineHeight];
IF h.affiliateThisPage THEN {
SF[symbols]; PT["!", h.dim.leftMargin, h.dim.bottomMargin - (3*h.dim.lineHeight/2)];
PTH[" affiliate member", bodyItalic]};
NewPage[h];
h.yTop ← h.dim.pageHeight - h.dim.topMargin;
h.firstOnPage ← h.lastOnPage ← NIL; h.affiliateThisPage ← FALSE;
h.pageNumber ← h.pageNumber + 1;
};
ReprintPage: PROC [h: Handle, pg: CARDINAL] = {
pd: PageData ← h.page[pg];
start: INT ← pd.start;
limit: INT ← h.page[pg+1].start;
IF pg < frontMatterPages THEN {PrintFrontMatter[h, pg]; RETURN};
IF start = -1 OR limit = -1 THEN NewPage[h]
ELSE {
h.prevInitial ← pd.initial;
h.pageNumber ← pd.number;
FOR i: INT IN [start..limit) DO
PressEntry[h, h.entry[i]];
ENDLOOP;
FinishPage[h]};
};
Problem: ERROR = CODE;
Xform: PROC [h: Handle, x, y: INT] RETURNS [xPrime, yPrime: INT] = {
SELECT h.pageLoc FROM
R90T => RETURN[17*36 - y, 11 * 36 - h.dim.fudgePoints + x];
R90B => RETURN[17*36 - y, x];
R270T => RETURN[y, 11 * 72 - h.dim.fudgePoints - x];
R270B => RETURN[y, 11 * 36 - x];
ENDCASE;
};
PrintText: PROC [h: Handle, t: ROPE, x, y: INT] = {
xT, yT: INT;
IF h.reallyPrinting THEN {
[xT, yT] ← Xform[h, x, y];
SirPress.PutText[p: h.press, textString: t, xCoordinateOfLeftEdge: xT, yCoordinateOfBaseline: yT, unit: SirPress.pt];
};
};
PrintHere: PROC [h: Handle, t: ROPE] = {
IF h.reallyPrinting THEN SirPress.PutTextHere[p: h.press, textString: t]};
SetFont: PROC [h: Handle, f: FontClass] = {
rot: Rotation ← (SELECT h.pageLoc FROM R90T, R90B => R90, ENDCASE => R270);
IF h.reallyPrinting THEN h.press.SetFontFromCode[h.fontCode[rot][f]];
};
Rectangle: PROC [h: Handle, xstart, ystart, xlen, ylen: INT] = {
xT, yT: INT;
xStop, yStop: INT;
[xT, yT] ← Xform[h, xstart, ystart];
[xStop, yStop] ← Xform[h, xstart + xlen, ystart + ylen];
IF h.reallyPrinting THEN
SELECT h.pageLoc FROM
R90T, R90B =>
h.press.PutRectangle[xstart: xStop, ystart: yT, xlen: ylen, ylen: xlen, unit: SirPress.pt];
R270T, R270B =>
h.press.PutRectangle[xstart: xT, ystart: yStop, xlen: ylen, ylen: xlen, unit: SirPress.pt];
ENDCASE;
};
NewPage: PROC [h: Handle] = {
IF h.reallyPrinting THEN {
h.pageParity ← (h.pageParity + 1) MOD 4;
SELECT h.pageParity FROM
1 => h.pageLoc ← R90B;
2 => {h.press.WritePage[]; h.pageLoc ← IF h.oneRot^ THEN R90B ELSE R270T};
3 => h.pageLoc ← IF h.oneRot^ THEN R90T ELSE R270B;
0 => {h.press.WritePage[]; h.pageLoc ← R90T};
ENDCASE}
ELSE {
h.page.count ← h.page.count + 1;
h.page[h.page.count] ← [
start: h.entry.count - 1, initial: h.prevInitial, number: h.pageNumber + 1];
};
};
MyBreak: IO.BreakProc -- [char: CHAR] RETURNS [IO.CharClass] -- = {
RETURN [SELECT char FROM
'\\, '|, '} => break,
'\t => sepr,
ENDCASE => other];
};
OpenFile: PROC [name: ROPE] RETURNS [st: STREAM] = {
st ← FS.StreamOpen[name, $read
! FS.Error => IF error.group # bug THEN CONTINUE]};
InputEntry: PROC [handle: Handle] = {
e: Entry;
IF handle.eof THEN RETURN;
IF handle.in = NIL THEN {
MessageWindow.Append[
message: "Please open a file first",
clearFirst: TRUE];
MessageWindow.Blink[ ];
ERROR ABORTED};
[] ← handle.in.SkipWhitespace[];
IF handle.in.EndOf[] THEN {handle.eof ← TRUE; GO TO done};
e ← ReadEntry[handle];
handle.entry[handle.entry.count] ← e;
handle.entry.count ← handle.entry.count + 1;
PressEntry[handle, e];
EXITS
done => NULL;
};
ReadEntry: PROC [handle: Handle] RETURNS [e: Entry] = {
one should SkipWhitespace before calling (and check for eof)
ENABLE IO.EndOfStream => {handle.eof ← TRUE; Quit[handle, "Syntax error "]};
st: STREAM ← handle.in;
ch: CHAR;
i: CARDINAL;
IF (ch ← st.GetChar[]) # '{ THEN Quit[handle, "Syntax error "];
i ← 0;
DO
e.phone[i] ← GetTokenRope[st, MyBreak].token;
SELECT (ch ← st.GetChar[]) FROM
'\\ => IF i = nLines-1 THEN Quit[handle, "Syntax error "];
'| => EXIT;
'} => RETURN;
ENDCASE => Quit[handle, "Syntax error "];
i ← i + 1;
ENDLOOP;
{
smash: BOOLFALSE;
FOR j: NAT IN SmallCount DO
IF smash THEN e.phone[j] ← NIL
ELSE IF e.phone[j] # NIL AND UC[Rope.Fetch[e.phone[j], 0]] = 'W THEN {
smash ← TRUE;
e.phone[j] ← NIL};
ENDLOOP;
};
i ← 0;
DO
e.name[i] ← GetTokenRope[st, MyBreak].token;
SELECT (ch ← st.GetChar[]) FROM
'\\ => IF i = nLines-1 THEN Quit[handle, "Syntax error "];
'| => EXIT;
'} => RETURN;
ENDCASE => Quit[handle, "Syntax error "];
i ← i + 1;
ENDLOOP;
i ← 0;
DO
e.addr[i] ← GetTokenRope[st, MyBreak].token;
SELECT (ch ← st.GetChar[]) FROM
'\\ => IF i = nLines-1 THEN Quit[handle, "Syntax error "];
'| => EXIT;
'} => RETURN;
ENDCASE => GO TO badsyntax;
i ← i + 1;
ENDLOOP;
e.town ← GetTokenRope[st, MyBreak].token;
IF st.GetChar[] = '} THEN RETURN;
e.zip ← GetTokenRope[st, MyBreak].token;
IF st.GetChar[] = '} THEN RETURN;
GO TO badsyntax;
EXITS
badsyntax => Quit[handle, "Syntax error "];
};
Quit: PROC [handle: Handle, reason: ROPENIL] = {
loc: INT = handle.in.GetIndex[];
handle.in.Close[]; handle.in ← NIL; handle.eof ← TRUE;
handle.tsOut.Put[[rope[reason]], [integer[loc]], [character['\n]]];
ERROR Problem};
copied from IOSearchImpl because it didn't handle empty tokens properly
GetToken: PROC [stream: STREAM, breakProc: IO.BreakProc, buffer: REF TEXT]
RETURNS[token: REF TEXT, charsSkipped: INT] = {
quit, include: BOOLFALSE;
anySeen: BOOLFALSE;
charsSkipped ← 0;
buffer.length ← 0;
DO
char: CHAR
stream.GetChar[ ! IO.EndOfStream => IF buffer.length > 0 THEN EXIT ELSE REJECT];
SELECT breakProc[char] FROM
break => {include ← FALSE; quit ← TRUE};
sepr => {include ← FALSE; quit ← anySeen };
other => {include ← TRUE; quit ← FALSE; anySeen ← TRUE};
ENDCASE => ERROR;
IF include THEN buffer ← RefText.InlineAppendChar[buffer, char]
ELSE
IF quit THEN stream.Backup[char] ELSE charsSkipped ← charsSkipped + 1;
IF quit THEN EXIT;
ENDLOOP;
RETURN[buffer, charsSkipped];
};
GetTokenRope: PUBLIC PROC [stream: STREAM, breakProc: IO.BreakProc]
RETURNS [token: ROPE, charsSkipped: INT] = {
buffer: REF TEXT = RefText.ObtainScratch[100];
{ ENABLE UNWIND => RefText.ReleaseScratch[buffer];
tokenText: REF TEXT;
[tokenText, charsSkipped] ← GetToken[stream, breakProc, buffer];
token ← IF tokenText.length = 0 THEN NIL ELSE Rope.FromRefText[tokenText];
};
RefText.ReleaseScratch[buffer];
RETURN [token, charsSkipped];
};
Commander.Register[key: "LandPrintDir", proc: MakeTool,
doc: "Create a church directory printer" ];
[ ] ← MakeTool[NIL]; -- and create an instance
END.