<> <> 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; <> 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: ROPE _ NIL] RETURNS [v: ViewerClasses.Viewer] = { ph: PromptHandle _ NEW [PromptRec _ [handle: handle]]; t: Buttons.Button _ Buttons.Create[ info: [ name: Rope.Concat[label, ":"], wy: handle.height, <> 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, <> 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, <> 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 <> ph: PromptHandle _ NARROW[clientData]; ViewerTools.SetSelection[ph.viewer]; -- force the selection END; ToggleBool: Buttons.ButtonProc = { switch: REF BOOL _ NARROW [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 <> 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] = { <> 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]; <> }; 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: STREAM _ NIL; 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; <> 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] = { <> 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: ROPE _ NIL] = { 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: ROPE _ NIL] = { loc: INT = st.GetIndex[]; st.Close[]; handle.tsOut.Put[[rope[reason]], [character[' ]]]; handle.tsOut.Put[[integer[loc]], [character['\n]]]; ERROR Problem}; <> GetToken: PROC [stream: STREAM, breakProc: IO.BreakProc, buffer: REF TEXT] RETURNS[token: REF TEXT, charsSkipped: INT] = { quit, include: BOOL _ FALSE; anySeen: BOOL _ FALSE; 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.