PrintForms.mesa;
Last Edited by: Sweet, October 8, 1984 2:01:09 pm PDT
DIRECTORY
Ascii,
BasicTime,
Buttons,
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound, Container, Create],
Convert,
FS,
IO,
MessageWindow,
PrintFormsDefs,
RefText,
Rope,
Rules USING [Create, Rule],
SafeStorage,
SirPress,
TSFont,
TSTypes,
TypeScript,
VFonts,
ViewerClasses USING [Viewer, ViewerClassRec],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [CreateViewer, PaintViewer],
ViewerTools USING [GetContents, MakeNewTextViewer, SetSelection];
PrintForms: CEDAR PROGRAM    
IMPORTS BasicTime, Buttons, Commander, Containers, Convert, FS, IO, MessageWindow, RefText, Rope, Rules, SafeStorage, SirPress, TSFont, TSTypes, TypeScript, VFonts, ViewerIO, ViewerOps, ViewerTools =
BEGIN OPEN PrintFormsDefs;
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.
Problem: PUBLIC ERROR = CODE;
MakeTool: Commander.CommandProc = BEGIN
rule: Rules.Rule;
my: Handle ← NEW[MyRec];
my.outer ← Containers.Create[[-- construct the outer container
name: "Forms 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;
faceNormal: CARDINAL = 0;
faceItalic: CARDINAL = 1;
faceBold: CARDINAL = 2;
faceBoldItalic: CARDINAL = 3;
LookupFonts: PROC [handle: Handle] = {
DoFont: PROC [class: FontClass, family: ROPE, size: INT, face: CARDINAL ← faceNormal, rotation: INT ← 5400] = {
handle.fontCode[class] ← handle.press.GetFontCode[
family: family,
size: size,
rotation: rotation,
face: face];
handle.fontInfo[class] ← TSFont.Lookup[
(SELECT face FROM
faceItalic => Rope.Concat[family, "I"],
faceBold => Rope.Concat[family, "B"],
faceBoldItalic => Rope.Concat[family, "BI"],
ENDCASE => family),
TSTypes.IntDimn[size, TSTypes.bp]];
};
DoFont[f0, "TimesRoman", 12, faceBold];
DoFont[f1, "Helvetica", 10];
DoFont[f2, "TimesRoman", 10, faceBold];
DoFont[f3, "TimesRoman", 10];
DoFont[f4, "Helvetica", 8];
DoFont[f5, "Helvetica", 8, faceNormal, 0];
DoFont[f6, "Helvetica", 10, faceItalic];
DoFont[bodyItalic, "TimesRoman", 10, faceItalic];
DoFont[symbols, "Math", 10];
};
MakeTypescript: PROC [handle: Handle] = BEGIN
handle.height ← handle.height + entryVSpace; -- space down from the top of the viewer
handle.ts ← TypeScript.Create[
info: [name: "PrintForms.ts", wy: handle.height, parent: handle.outer, border: FALSE ]];
[handle.tsIn, handle.tsOut] ← ViewerIO.CreateViewerStreams [
name: "PrintForms.ts", viewer: handle.ts, backingFile: "PrintForms.ts", editedStream: FALSE];
Containers.ChildXBound[handle.outer, handle.ts];
Containers.ChildYBound[handle.outer, handle.ts];
END;
MakeCommands: PROC [handle: Handle] = BEGIN
initialData: Rope.ROPE = NIL;
wx: INT ← 0;
NewLine: PROC = {handle.height ← handle.height + entryHeight + entryVSpace; wx ← 0};
LabeledItem: PROC [label: ROPE, width: INT, data: ROPENIL]
RETURNS [v: ViewerClasses.Viewer] = {
ph: PromptHandle ← NEW [PromptRec ← [handle: handle]];
t: Buttons.Button ← Buttons.Create[
info: [
name: Rope.Concat[label, ":"],
wy: handle.height,
default the width so that it will be computed for us --
wh: entryHeight, -- specify rather than defaulting so line is uniform
wx: wx,
parent: handle.outer,
border: FALSE ],
proc: Prompt,
clientData: ph]; -- this will be passed to our button proc
wx ← wx + t.ww + entryHSpace;
v ← ViewerTools.MakeNewTextViewer[ [
parent: handle.outer,
wx: wx,
wy: handle.height,
ww: width*VFonts.CharWidth['0],
wh: entryHeight,
data: data,
scrollable: FALSE,
border: FALSE]];
ph.viewer ← v;
wx ← wx + v.ww + entryHSpace};
Cmd: PROC [label: ROPE, proc: Buttons.ButtonProc] = {
t: Buttons.Button ← Buttons.Create[
info: [
name: label,
wx: wx,
wy: handle.height,
default the width so that it will be computed for us --
wh: entryHeight, -- specify rather than defaulting so line is uniform
parent: handle.outer,
border: TRUE ],
proc: proc,
clientData: handle]; -- this will be passed to our button proc
wx ← wx + t.ww + entryHSpace};
Bool: PROC [label: ROPE, initial: BOOL] RETURNS [flag: REF BOOL] = {
t: Buttons.Button;
flag ← NEW[BOOL ← initial];
t ← Buttons.Create[
info: [
name: label,
wx: wx,
wy: handle.height,
default the width so that it will be computed for us --
wh: entryHeight, -- specify rather than defaulting so line is uniform
parent: handle.outer,
border: TRUE ],
proc: ToggleBool,
clientData: flag]; -- this will be passed to our button proc
Buttons.SetDisplayStyle[
button: t, style: IF initial THEN $WhiteOnBlack ELSE $BlackOnWhite, paint: FALSE];
wx ← wx + t.ww + entryHSpace};
NewLine[];
Cmd["Print", DoIt];
NewLine[];
handle.cmd.inputFile ← LabeledItem["input", 50, "///FUMC/"];
NewLine[];
handle.cmd.pressFile ← LabeledItem["press", 50, "///FUMC/"];
NewLine[];
handle.cmd.firstCaller ← LabeledItem["first caller", 5, "20"];
handle.cmd.callers ← LabeledItem["callers", 40, "///FUMC/CallerNames.txt"];
NewLine[];
END;
Prompt: 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
ph: PromptHandle ← NARROW[clientData];
ViewerTools.SetSelection[ph.viewer];  -- force the selection
END;
ToggleBool: Buttons.ButtonProc = {
switch: REF BOOLNARROW [clientData];
switch^ ← ~switch^;
Buttons.SetDisplayStyle[
button: NARROW[parent],
style: IF switch^ THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
DoIt: 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];
count: CARDINAL ← 0;
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;
IF pName # NIL AND Rope.Length[pName] # 0 THEN {
handle.out ← FS.StreamOpen[fileName: pName, accessOptions: $create];
handle.press ← SirPress.Create[outputStream: handle.out, fileNameForHeaderPage: pName];
handle.date ← Convert.RopeFromTime[BasicTime.Now[], $years, $days];
handle.press.SetPageSize[110, 85];
LookupFonts[handle];
handle.callerName ← ParseCallerNames[handle];
handle.firstCaller ← Val[handle.cmd.firstCaller, 20];
handle.entryY ← firstY; handle.entriesOnPage ← 0;
handle.prevCaller ← 0; handle.affiliateThisPage ← FALSE;
}
ELSE Quit[handle, "No output file"];
handle.tsOut.PutText["Processing:"];
WHILE ~handle.eof DO
ProcessEntry[handle];
count ← count + 1;
IF count MOD 50 = 0 THEN handle.tsOut.PutChar['.];
ENDLOOP;
IF handle.press # NIL THEN {
FinishPage[handle];
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]]];
END;
MWidth: 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.mica]];
};
SplatRope: PUBLIC PROCEDURE [h: Handle, x, y: INT, f: FontClass, s: ROPE] = {
h.press.SetFontFromCode[h.fontCode[f]];
SirPress.PutText[ -- rotated 90 degrees
p: h.press,
textString: s,
xCoordinateOfLeftEdge: pageWidth-y,
yCoordinateOfBaseline: x]};
DrawBox: PUBLIC PROCEDURE [h: Handle, x, y, width, height: INT] = {
SirPress.PutRectangle[ -- rotated 90 degrees
p: h.press,
xstart: pageWidth-y-height,
ystart: x,
xlen: height,
ylen: width]};
RJString: PROCEDURE [h: Handle, x, y: INT, f: FontClass, s: ROPE, width: INT] = {
SplatRope[h: h, x: x + width - MWidth[h, s, f], y: y, f: f, s: s]};
LJString: PROCEDURE [h: Handle, x, y: INT, f: FontClass, s: ROPE] = {
SplatRope[h: h, x: x, y: y, f: f, s: s]};
CenterString: PROCEDURE [h: Handle, x, y: INT, f: FontClass, s: ROPE, width: INT] = {
delta: INT = width - MWidth[h, s, f];
SplatRope[h: h, x: x + delta/2, y: y, f: f, s: s]};
Place: TYPE = RECORD [x, y: INT];
callerNamePlace: Place = [x: 5094, y: 19910];
recruiterNamePlace: Place = [x: 5094, y: 19483];
callerPhonePlace: Place = [x: 14341, y: 19910];
recruiterPhonePlace: Place = [x: 14341, y: 19483];
datePlace: Place = [x: 23942, y: 2057];
firstY: INT = 17883;
activityX: INT = 969;
levelX: INT = 1396;
dinnerX: INT = 1823;
ageX: INT = 2249;
phoneX: INT = 2676;
nameX: INT = 5237;
addrX: INT = 12207;
commentX: INT = 21026;
entryDelta: INT = 1565;
lineDelta: INT = 427;
PrintBoilerplate: PUBLIC PROC [h: Handle] = {
Copied from Castilleja output
SplatRope[h: h, x: 827, y: 20514, f: f0, s: "First United Methodist Church, Palo Alto"];
SplatRope[h: h, x: 22022, y: 20514, f: f0, s: "1985 Financial Campaign"];
SplatRope[h: h, x: 2818, y: 19910, f: f1, s: "Caller name:"];
SplatRope[h: h, x: 12776, y: 19910, f: f1, s: "Phone:"];
SplatRope[h: h, x: 2818, y: 19483, f: f1, s: "Reports to:"];
SplatRope[h: h, x: 12776, y: 19483, f: f1, s: "Phone:"];
SplatRope[h: h, x: 22947, y: 19127, f: f1, s: "Comments"];
SplatRope[h: h, x: 3245, y: 18701, f: f1, s: "Phone"];
SplatRope[h: h, x: 8082, y: 18701, f: f1, s: "Name"];
SplatRope[h: h, x: 14127, y: 18701, f: f1, s: "Address"];
SplatRope[h: h, x: 1396, y: 2200, f: f1, s: "Activity level"];
SplatRope[h: h, x: 4668, y: 2200, f: f1, s: "Contribution in 1984"];
SplatRope[h: h, x: 9504, y: 2200, f: f1, s: "Expected Campaign contact mode"];
SplatRope[h: h, x: 16190, y: 2200, f: f1, s: "Age range"];
SplatRope[h: h, x: 1396, y: 1880, f: f4, s: "a"];
SplatRope[h: h, x: 1680, y: 1880, f: f4, s: "= active"];
SplatRope[h: h, x: 4668, y: 1880, f: f4, s: "p"];
SplatRope[h: h, x: 4952, y: 1880, f: f4, s: "= pledge"];
SplatRope[h: h, x: 9504, y: 1880, f: f4, s: "d"];
SplatRope[h: h, x: 9789, y: 1880, f: f4, s: "= dinner"];
SplatRope[h: h, x: 16190, y: 1880, f: f4, s: "k"];
SplatRope[h: h, x: 16474, y: 1880, f: f4, s: "= middle/ high school"];
SplatRope[h: h, x: 1396, y: 1559, f: f4, s: "b"];
SplatRope[h: h, x: 1680, y: 1559, f: f4, s: "= infrequent"];
SplatRope[h: h, x: 4668, y: 1559, f: f4, s: "c"];
SplatRope[h: h, x: 4952, y: 1559, f: f4, s: "= contribution"];
SplatRope[h: h, x: 9504, y: 1559, f: f4, s: "h"];
SplatRope[h: h, x: 9789, y: 1559, f: f4, s: "= home visit"];
SplatRope[h: h, x: 16190, y: 1559, f: f4, s: "y"];
SplatRope[h: h, x: 16474, y: 1559, f: f4, s: "= college to age 30"];
SplatRope[h: h, x: 1396, y: 1239, f: f4, s: "c"];
SplatRope[h: h, x: 1680, y: 1239, f: f4, s: "= inactive"];
SplatRope[h: h, x: 4668, y: 1239, f: f4, s: "0"];
SplatRope[h: h, x: 4952, y: 1239, f: f4, s: "= no traceable contribution"];
SplatRope[h: h, x: 9504, y: 1239, f: f4, s: "i"];
SplatRope[h: h, x: 9789, y: 1239, f: f4, s: "= inactive"];
SplatRope[h: h, x: 16190, y: 1239, f: f4, s: "a"];
SplatRope[h: h, x: 16474, y: 1239, f: f4, s: "= 30 to 70"];
SplatRope[h: h, x: 1396, y: 919, f: f4, s: "-"];
SplatRope[h: h, x: 1680, y: 919, f: f4, s: "= no data"];
SplatRope[h: h, x: 4668, y: 919, f: f4, s: "-"];
SplatRope[h: h, x: 4952, y: 919, f: f4, s: "= no data"];
SplatRope[h: h, x: 9504, y: 919, f: f4, s: "-"];
SplatRope[h: h, x: 9789, y: 919, f: f4, s: "= no data"];
SplatRope[h: h, x: 16190, y: 919, f: f4, s: "s"];
SplatRope[h: h, x: 16474, y: 919, f: f4, s: "= post 70"];
SplatRope[h: h, x: 20386, y: 635, f: bodyItalic, s: "Italic name = Constituent"];
SplatRope[h: h, x: 16190, y: 599, f: f4, s: "-"];
SplatRope[h: h, x: 16474, y: 599, f: f4, s: "= no data"];
SplatRope[h: h, x: 969, y: 20194, f: f5, s: "Activity"];
SplatRope[h: h, x: 1396, y: 20194, f: f5, s: "'84 Contrib"];
SplatRope[h: h, x: 1823, y: 20194, f: f5, s: "Exp. Mode"];
SplatRope[h: h, x: 2249, y: 20194, f: f5, s: "Age"];
SplatRope[h: h, x: 17790, y: 20194, f: f5, s: "count - came"];
SplatRope[h: h, x: 18110, y: 20194, f: f5, s: "Dinner date/"];
SplatRope[h: h, x: 18786, y: 20194, f: f5, s: "date/time"];
SplatRope[h: h, x: 19106, y: 20194, f: f5, s: "Home visit"];
SplatRope[h: h, x: 20600, y: 20194, f: f5, s: "Inactive"];
SplatRope[h: h, x: 19746, y: 19696, f: f5, s: "rec'd"];
SplatRope[h: h, x: 20102, y: 20194, f: f5, s: "Date pledge"];
DrawBox[h: h, x: 791, y: 20265, width: 25925, height: 71];
DrawBox[h: h, x: 2534, y: 19305, width: 14936, height: 36];
DrawBox[h: h, x: 791, y: 18274, width: 25925, height: 71];
DrawBox[h: h, x: 17470, y: 17171, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 16745, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 15607, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 15180, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 14042, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 13615, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 12477, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 12050, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 10912, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 10486, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 9348, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 8921, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 7783, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 7356, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 6218, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 5791, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 4653, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 4227, width: 25925, height: 36];
DrawBox[h: h, x: 17470, y: 3089, width: 996, height: 36];
DrawBox[h: h, x: 791, y: 2626, width: 25996, height: 71];
DrawBox[h: h, x: 791, y: 2697, width: 71, height: 17639];
DrawBox[h: h, x: 1254, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 1680, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 2107, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 2534, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 5094, y: 2697, width: 36, height: 16643];
DrawBox[h: h, x: 12065, y: 2697, width: 36, height: 16643];
DrawBox[h: h, x: 17470, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 18466, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 19462, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 20457, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 20884, y: 2697, width: 36, height: 17639];
DrawBox[h: h, x: 26716, y: 2697, width: 71, height: 17639];
end of copy
};
UC: PROC [c: CHAR] RETURNS [CHAR] = {
RETURN[IF c IN ['a..'z] THEN VAL[c.ORD - ORD['a] + ORD['A]] ELSE c]};
PressNames: PROC [h: Handle, name: ARRAY [0..4) OF ROPE] = {
PTH: PROC [t: ROPE, f: FontClass] = {
h.press.SetFontFromCode[h.fontCode[f]];
SirPress.PutTextHere[p: h.press, textString: t]};
NameBreak: IO.BreakProc = {
RETURN [SELECT char FROM
'&, ', => break,
'\t => sepr, -- blanks are allowed in names
ENDCASE => other]};
default: FontClass ← nameFont;
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;
x: INT ← nameX;
y: INT ← h.entryY;
fc: FontClass;
ns ← IO.RIS[name[0]];
[t, default, affiliate, bk] ← GetName[]; -- last name
IF affiliate THEN {
SplatRope[h: h, s: "!", x: x, y: y, f: symbols];
x ← x + MWidth[h, "!", symbols]};
SplatRope[h: h, s: t, x: x, y: y, f: default];
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? NO.
FOR i: CARDINAL IN [1..4) WHILE name[i] # NIL DO
y ← y - lineDelta;
x ← nameX;
ns ← IO.RIS[name[i], ns];
[t, fc, affiliate, bk] ← GetName[];
IF t = NIL THEN LOOP;
IF affiliate THEN {
SplatRope[h: h, s: "!", x: x, y: y, f: symbols];
x ← x + MWidth[h, "!", symbols]};
SplatRope[h: h, s: t, x: x, y: y, f: fc];
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..4) OF ROPE] = {
y: INT ← h.entryY;
FOR i: INT IN [0..4) WHILE phone[i] # NIL DO
p: ROPE = phone[i];
x: INT ← phoneX;
IF UC[Rope.Fetch[p, 0]] = 'X THEN x ← phoneX + 2540/4;
SplatRope[h: h, s: p, x: x, y: y, f: bodyFont];
y ← y - lineDelta;
ENDLOOP};
PressEntry: PROC [h: Handle, e: Entry] = {
flagged: BOOLEAN;
Flag: PROC = {
IF flagged THEN RETURN;
flagged ← TRUE;
h.tsOut.Put[[character['\n]], [rope[e.name[0]]]]};
y: INT;
PTH: PROC [t: ROPE, f: FontClass] = {
h.press.SetFontFromCode[h.fontCode[f]];
SirPress.PutTextHere[p: h.press, textString: t]};
IF h.prevCaller = 0 THEN h.prevCaller ← e.caller;
IF h.entriesOnPage = 10 OR h.prevCaller # e.caller THEN {
FinishPage[h];
h.prevCaller ← e.caller};
SplatRope[h: h, s: Rope.FromChar[e.activity], x: activityX, y: h.entryY, f: bodyFont];
IF e.level IN ['1..'9] THEN e.level ← 'p;
SplatRope[h: h, s: Rope.FromChar[e.level], x: levelX, y: h.entryY, f: bodyFont];
SplatRope[h: h, s: Rope.FromChar[e.dinner], x: dinnerX, y: h.entryY, f: bodyFont];
SplatRope[h: h, s: Rope.FromChar[e.age], x: ageX, y: h.entryY, f: bodyFont];
PressPhone[h, e.phone];
PressNames[h, e.name];
y ← h.entryY;
FOR i: CARDINAL IN [0..4) DO
IF e.addr[i] = NIL THEN EXIT;
SplatRope[h: h, s: e.addr[i], x: addrX, y: y, f: bodyFont];
y ← y - lineDelta;
ENDLOOP;
IF e.town # NIL THEN {
PL: PROC [t: ROPE] = {SplatRope[h: h, s: t, x: addrX, y: y, f: bodyFont]};
SELECT TRUE FROM
Rope.Equal[e.town, "PA"] => PL["Palo Alto, CA "];
Rope.Equal[e.town, "MP"] => PL["Menlo Park, CA "];
Rope.Equal[e.town, "S"] => PL["Stanford, CA "];
Rope.Equal[e.town, "LA"] => PL["Los Altos, CA "];
Rope.Equal[e.town, "LAH"] => PL["Los Altos Hills, CA "];
Rope.Equal[e.town, "C"] => PL["Cupertino, CA "];
Rope.Equal[e.town, "Svl"] => PL["Sunnyvale, CA "];
Rope.Equal[e.town, "A"] => PL["Atherton, CA "];
Rope.Equal[e.town, "EPA"] => PL["Palo Alto, CA "];
Rope.Equal[e.town, "RC"] => PL["Redwood City, CA "];
Rope.Equal[e.town, "MV"] => PL["Mountain View, CA "];
Rope.Equal[e.town, "SC"] => PL["Santa Clara, CA "];
Rope.Equal[e.town, "SJ"] => PL["San Jose, CA "];
Rope.Equal[e.town, "W"] => PL["Woodside, CA "];
Rope.Equal[e.town, "PV"] => PL["Portola Valley, CA "];
Rope.Equal[e.town, "LG"] => PL["Los Gatos, CA "];
Rope.Equal[e.town, "SF"] => PL["San Francisco, CA "];
Rope.Equal[e.town, "SM"] => PL["San Mateo, CA "];
ENDCASE => {Flag[]; PL["???? "]};
};
IF e.zip # NIL THEN {
PTH[t: " ", f: bodyFont];
PTH[t: e.zip, f: bodyFont]};
IF e.comment # NIL THEN {
SplatRope[h: h, s: e.comment, x: commentX, y: h.entryY, f: bodyItalic]};
h.entryY ← h.entryY - entryDelta;
h.entriesOnPage ← h.entriesOnPage + 1;
};
FinishPage: PROC [h: Handle] = {
caller: CallerNumber = h.prevCaller;
recruiter: CallerNumber = h.callerName[caller].recruiter;
-- do caller stuff
IF h.affiliateThisPage THEN {
SplatRope[h: h, x: 22022, y: 1275, f: symbols, s: "!"];
SplatRope[h: h, x: 22235, y: 1275, f: f1, s: "= Affiliate Member"]};
SplatRope[
h: h, x: callerNamePlace.x, y: callerNamePlace.y,
s: h.callerName[caller].name, f: nameFont];
SplatRope[
h: h, x: recruiterNamePlace.x, y: recruiterNamePlace.y,
s: h.callerName[recruiter].name, f: nameFont];
SplatRope[
h: h, x: callerPhonePlace.x, y: callerPhonePlace.y,
s: h.callerName[caller].phone, f: bodyFont];
SplatRope[
h: h, x: recruiterPhonePlace.x, y: recruiterPhonePlace.y,
s: h.callerName[recruiter].phone, f: bodyFont];
SplatRope[
h: h, x: datePlace.x, y: datePlace.y,
s: h.date, f: f1];
PrintBoilerplate[h];
h.press.WritePage[];
h.entryY ← firstY;
h.affiliateThisPage ← FALSE;
h.entriesOnPage ← 0;
};
MyBreak: IO.BreakProc -- [char: CHAR] RETURNS [IO.CharClass] -- = {
RETURN [SELECT char FROM
'\\, '|, '}, '\n => 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]};
ProcessEntry: 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];
IF handle.press # NIL AND e.caller >= handle.firstCaller THEN 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;
caller: ROPE;
i: CARDINAL;
IF (ch ← st.GetChar[]) # '{ THEN Quit[handle, "Syntax error "];
caller ← GetTokenRope[st, MyBreak].token;
IF caller # NIL THEN
e.caller ← Convert.IntFromRope[caller ! Convert.Error => Quit[handle, "bad caller #"]];
IF (ch ← st.GetChar[]) # '| THEN Quit[handle, "Syntax error "];
BEGIN -- get campaign info
IF (ch ← st.GetChar[]) = '| THEN GO TO done;
e.activity ← ch;
IF (ch ← st.GetChar[]) = '| THEN GO TO done;
e.level ← ch;
IF (ch ← st.GetChar[]) = '| THEN GO TO done;
e.dinner ← ch;
IF (ch ← st.GetChar[]) = '| THEN GO TO done;
e.age ← ch;
IF (ch ← st.GetChar[]) # '| THEN Quit[handle, "Syntax error "];
EXITS
done => NULL;
END;
i ← 0;
DO
e.phone[i] ← GetTokenRope[st, MyBreak].token;
SELECT (ch ← st.GetChar[]) FROM
'\\ => IF i = 2 THEN Quit[handle, "Syntax error "];
'| => EXIT;
'} => RETURN;
ENDCASE => Quit[handle, "Syntax error "];
i ← i + 1;
ENDLOOP;
i ← 0;
DO
e.name[i] ← GetTokenRope[st, MyBreak].token;
SELECT (ch ← st.GetChar[]) FROM
'\\ => IF i = 3 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 = 3 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;
e.mailing ← GetTokenRope[st, MyBreak].token;
IF st.GetChar[] = '} THEN RETURN;
e.comment ← GetTokenRope[st, MyBreak].token;
IF st.GetChar[] # '} THEN Quit[handle, "Syntax error "];
EXITS
badsyntax => Quit[handle, "Syntax error "];
};
ParseCallerNames: PROC [h: Handle] RETURNS [n: REF CallerNameRec] = {
cnfile: ROPE ← ViewerTools.GetContents[h.cmd.callers];
ch: CHAR;
r: INT ← 0;
index: INT;
c, p: ROPE;
st: STREAM;
n ← NEW[CallerNameRec ← ALL[[NIL, NIL, 0]]];
st ← OpenFile[cnfile];
IF st = NIL THEN Quit2[h, st, "No caller names"];
WHILE ~st.EndOf[] DO
ENABLE IO.Error => Quit2[h, st, "invalid callernames"];
c ← p ← NIL;
[] ← st.SkipWhitespace[];
IF st.EndOf[] THEN RETURN;
index ← st.GetInt[];
IF NOT (index IN [0..100)) THEN Quit2[h, st, "Index invalid in callernames"];
IF st.GetChar[] # '\t THEN Quit2[h, st, "Missing tab in callernames"];
c ← GetTokenRope[st, MyBreak].token;
BEGIN
IF ~st.EndOf[] THEN SELECT (ch ← st.GetChar[]) FROM
'\n => GO TO done;
'| => NULL;
ENDCASE => Quit2[h, st, "Syntax error in callernames"];
p ← GetTokenRope[st, MyBreak].token;
IF ~st.EndOf[] THEN SELECT (ch ← st.GetChar[]) FROM
'\n => GO TO done;
'| => NULL;
ENDCASE => Quit2[h, st, "Syntax error in callernames"];
[] ← st.SkipWhitespace[];
IF st.EndOf[] THEN RETURN;
r ← st.GetInt[];
IF st.GetChar[] # '\n THEN Quit2[h, st, "Missing CR in callernames"];
EXITS
done => NULL;
END;
n[index] ← [name: c, phone: p, recruiter: r];
ENDLOOP;
st.Close[]};
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};
Quit2: PROC [handle: Handle, st: STREAM, reason: ROPENIL] = {
loc: INT = st.GetIndex[];
st.Close[];
handle.tsOut.Put[[rope[reason]], [character[' ]]];
handle.tsOut.Put[[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: "PrintForms", proc: MakeTool,
doc: "Create a campaign forms printer" ];
[ ] ← MakeTool[NIL]; -- and create an instance
END.