DIRECTORY Buttons USING [ButtonProc, Create, Button, ReLabel], Commander USING [CommandProc, Handle, Register], ConvertUnsafe USING [AppendRope], Environment USING [Block, bytesPerPage, charsPerWord, wordsPerPage], FileStream USING [SetLength], Inline USING [LongDivMod], IO USING [STREAM, Flush, Put, PutChar, PutRope, GetChar, CharsAvail, rope, char, string, card, NUL, SP, UserAbort], LongString USING [AppendString, EquivalentStrings], LongStorage USING [CopyString, FreeString, FreeStringNil, FreePages, Pages], MailFile USING [Create, Destroy, Error, GetAttributes, Handle, MsgBody, TOC, TOCEntry], Press USING [ Abort, BadParameters, Character, Finish, FlushFontBuffers, FontIndex, FontSlope, FontWeight, GetCurrentPageNumber, GetCurrentPosition, GetHeightOfFont, GetWidthOfCharacter, Initialize, InternalError, Mica, micasPerInch, Mode, pageHeight, pageWidth, PartBufferOverflow, PieceOfLine, Points, PutFontInTable, Reset, SetCurrentFont, SetCurrentPosition, SetCurrentPageNumber, SetCurrentTabWidth, SetHeaderText, SetMargins, SetMode, SkipSomeSpace, SetTrailerText, Start], PressUtilities USING [ hardcopyFont, hardcopyHost, IsPressFile, SendPressStream, ServerBusy, ServerTimeout, ServerTrouble, SetupFontsForNonProgDisk, SetupHardCopyOptions], PrintOps USING [ DataEnd, Direction, Format, GetStatus, Margins, Parameters, ParametersHandle, PressProcsObject], Process USING [Yield, Detach], Rope USING [ROPE, Length, Fetch], Segments USING [ FileNameProblem, FHandle, GetFileTimes, LockFile, NewFile, ReleaseFile, UnlockFile], Streams USING [ CreateStream, Destroy, GetIndex, NewStream, Read, ReadWrite, GetBlock, SetIndex, Handle, Write], String USING [AppendChar, AppendString, EqualString], Time USING [Append, Current, Packed, Unpack], UserCredentials USING [GetUserCredentials], UserProfile, ViewerIO USING [CreateMessageWindowStream], ViewerTools USING [GetSelectionContents]; PrintControl: MONITOR IMPORTS Buttons, Commander, ConvertUnsafe, FileStream, Inline, IO, LongStorage, LongString, MailFile, Press, PressUtilities, PrintOps, Process, Rope, Segments, Streams, String, Time, UserCredentials, UserProfile, ViewerIO, ViewerTools EXPORTS PrintOps = BEGIN OPEN IO; NUL: CHARACTER = IO.NUL; Mica: TYPE = Press.Mica; Inch: Mica = Press.micasPerInch; charsPerWord: CARDINAL = Environment.charsPerWord; bytesPerPage: CARDINAL = Environment.bytesPerPage; debugging: BOOLEAN _ FALSE; abortPlease: BOOLEAN _ FALSE; busy: BOOLEAN _ FALSE; printButton: Buttons.Button; controllingExec: Commander.Handle; -- set up by CommandProc out: PUBLIC IO.STREAM; -- controllingExec.out. set up by commandProc. SetDebugging: PROCEDURE [d: BOOLEAN] = BEGIN OPEN IO; debugging _ d; out.Put[rope["Debugging "], rope[IF debugging THEN "on\n" ELSE "off\n"]]; RETURN END; SetFont: PROCEDURE [f: STRING, p: PrintOps.ParametersHandle] = BEGIN IF font # NIL AND LongString.EquivalentStrings[f, font] THEN RETURN; LongStorage.FreeString[font]; font _ LongStorage.CopyString[f]; fontChanged _ TRUE; RETURN END; SetHost: PROCEDURE [h: STRING, p: PrintOps.ParametersHandle] = BEGIN LongStorage.FreeString[outputFile]; outputFile _ NIL; transmitting _ TRUE; IF printerName # NIL AND ~LongString.EquivalentStrings[h, printerName] THEN FinishFile[]; LongStorage.FreeString[printerName]; printerName _ LongStorage.CopyString[h]; haveStatus _ FALSE; RETURN END; SetOutputFile: PROCEDURE [f: STRING, p: PrintOps.ParametersHandle] = BEGIN OPEN String; FinishFile[]; LongStorage.FreeString[printerName]; printerName _ NIL; LongStorage.FreeString[outputFile]; FOR i: CARDINAL IN [0..f.length) DO IF f[i] = '. THEN {IF i = f.length - 1 THEN AppendString[f, "press"L]; EXIT} REPEAT FINISHED => {AppendChar[f, '.]; AppendString[f, "press"L]}; ENDLOOP; outputFile _ LongStorage.CopyString[f]; transmitting _ FALSE; out.Put[rope["Output to "], string[f], char['\n]]; out.Flush[]; RETURN END; SetLandscape: PROCEDURE [c: CARDINAL, p: PrintOps.ParametersHandle] = BEGIN p.mode _ landscape; IF ~fontSpecified THEN SetFont[lDefault.font, p]; p.columns _ c; p.margins _ lDefault.margins; RETURN END; SetPortrait: PROCEDURE [c: CARDINAL, p: PrintOps.ParametersHandle] = BEGIN p.mode _ portrait; IF ~fontSpecified THEN SetFont[pDefault.font, p]; p.columns _ c; p.margins _ pDefault.margins; END; SetNonProg: PROCEDURE [p: PrintOps.ParametersHandle] = BEGIN p.nonprog _ TRUE; p.trailers _ FALSE; PressUtilities.SetupFontsForNonProgDisk[p.mode = landscape]; fontChanged _ FALSE; IF p.mode = portrait THEN p.margins _ nonProgMargins; END; SetMail: PROCEDURE [p: PrintOps.ParametersHandle] = INLINE {p.mail _ TRUE}; SetTabWidth: PROCEDURE [c: CARDINAL, p: PrintOps.ParametersHandle] = BEGIN p.tab _ c; END; SetCopies: PROCEDURE [c: CARDINAL, p: PrintOps.ParametersHandle] = BEGIN p.copies _ c; END; sides: CARDINAL; PropList: PROCEDURE [POINTER] RETURNS [CARDINAL] _ NIL; SetSides: PROCEDURE [s: CARDINAL, p: PrintOps.ParametersHandle] = BEGIN sides _ s; PropList _ IF sides = 0 THEN NIL ELSE MakePropertyList; END; AppendBooleanProperty: PROCEDURE [s, prop: STRING, b: BOOLEAN] = BEGIN OPEN String; AppendChar[s, '(]; AppendString[s, prop]; AppendChar[s, IO.SP]; AppendString[s, IF b THEN "TRUE"L ELSE "FALSE"L]; AppendChar[s, ')]; RETURN END; MakePropertyList: PROCEDURE [p: POINTER] RETURNS [bytes: CARDINAL] = BEGIN OPEN String; passwordPtr: TYPE = POINTER TO MACHINE DEPENDENT RECORD [a, b: CARDINAL]; s: STRING _ p; s^ _ [length: 0, maxlength: 508, text:]; AppendChar[s, '(]; AppendBooleanProperty[s, "DUPLEX"L, sides = 2]; AppendChar[s, ')]; bytes _ s.length + 4; LOOPHOLE[p, passwordPtr]^ _ [125314B, 170377B]; RETURN END; pressFileActive: BOOLEAN; pressFileName: LONG STRING _ NIL; AbortFile: PROCEDURE [s: Rope.ROPE] = BEGIN out.PutRope[s]; out.Flush[]; Press.Abort[]; pressFileActive _ FALSE; END; PressThisFile: PROCEDURE [file: STRING, selection: Rope.ROPE] = BEGIN ENABLE BEGIN Segments.FileNameProblem[] => {out.Put[rope[" Can't find "], string[name]]; out.Flush[]; CONTINUE}; Press.BadParameters => {AbortFile["Bad parameters"]; IF ~debugging THEN CONTINUE}; Press.InternalError => {AbortFile["Internal Error"]; IF ~debugging THEN CONTINUE}; Press.PartBufferOverflow => {AbortFile["Document too complicated"]; IF ~debugging THEN CONTINUE}; END; isPressFile: BOOLEAN; lastPage: CARDINAL; header: STRING _ [60]; fh: Segments.FHandle; createTime: Time.Packed; IF transmitting AND ~haveStatus AND ~PrintOps.GetStatus[] THEN BEGIN IF controllingExec # NIL THEN { execIn: IO.STREAM = controllingExec.in; WHILE execIn.CharsAvail[] DO [] _ execIn.GetChar[] ENDLOOP; }; ERROR Abort; END; IF String.EqualString[file, "$$$"L] THEN {PressCurrentSelection[selection]; RETURN}; fh _ Segments.NewFile[file]; createTime _ Segments.GetFileTimes[fh].create; haveStatus _ TRUE; String.AppendString[header, file]; String.AppendString[header, " "L]; Time.Append[header, Time.Unpack[createTime]]; IF pressFileActive AND outputFile = NIL AND (Streams.GetIndex[ outputStream] / bytesPerPage) > 200 THEN FinishFile[]; out.Put[rope["Pressing "], string[file]]; ShowParameters[]; out.PutRope["..."]; out.Flush[]; [isPressFile, lastPage] _ PressUtilities.IsPressFile[fh]; IF isPressFile THEN BEGIN out.PutRope["already in Press format..."]; IF transmitting THEN BEGIN OPEN Streams, PressUtilities; s: Streams.Handle = CreateStream[fh, Read]; aborted: BOOLEAN _ FALSE; out.Put[rope["sending to "], string[printerName], rope["..."]]; out.Flush[]; IF AbortRequested[] THEN SIGNAL Abort; SendPressStream[ s, lastPage, printerName, cParameters.copies, PropList, file, createTime ! ServerBusy => {Wait["busy", 8]; RESUME}; ServerTimeout => {Wait["not responding", 0]; RESUME}; ServerTrouble => { IF message # NIL THEN out.Put[string[message]]; out.Flush[]; aborted _ TRUE; CONTINUE}; UNWIND => {Press.Abort[]; Streams.Destroy[s]}]; out.PutRope[IF aborted THEN "Aborted\n" ELSE "Done\n"]; out.Flush[]; Streams.Destroy[s]; END ELSE {out.PutRope["skipped"]; out.Flush[]; Segments.ReleaseFile[fh]}; RETURN END; Press.SetHeaderText[NIL, FALSE]; IF pressFileActive THEN THROUGH [0..neededFFs) DO Press.Character['\f]; Press.SetTrailerText[NIL, FALSE]; -- keep trailer on last page ENDLOOP; Press.SetCurrentPageNumber[1]; IF cParameters.headers THEN Press.SetHeaderText[header, TRUE]; IF cParameters.trailers THEN Press.SetTrailerText[header, TRUE]; BEGIN OPEN Press; pages: CARDINAL; IF fontChanged THEN InstallFont[font]; SetMode[cParameters.columns, cParameters.betweenColumns, cParameters.mode]; SetMargins[ cParameters.margins[left], cParameters.margins[right], cParameters.margins[top], cParameters.margins[bottom]]; IF ~pressFileActive THEN StartFile[file]; SetCurrentFont[defaultFont, cParameters.weight, cParameters.slope]; SetCurrentTabWidth[GetWidthOfCharacter[' ]*cParameters.tab]; out.Put[card[pages _ PrintFile[fh]], rope[" page"]]; IF pages # 1 THEN out.PutChar['s]; END; out.PutChar['\n]; out.Flush[]; RETURN END; transmitting: BOOLEAN; bufferStream: Streams.Handle; outputStream: Streams.Handle; StartFile: PROCEDURE [name: STRING] = BEGIN OPEN Streams; s: STRING = [40]; IF outputFile = NIL THEN { LongString.AppendString[s, bufferFile]; IF bufferStream = NIL THEN bufferStream _ NewStream[s, ReadWrite]; outputStream _ bufferStream} ELSE { LongString.AppendString[s, outputFile]; outputStream _ NewStream[s, IF transmitting THEN ReadWrite ELSE Write]}; Press.Start[name, outputStream]; pressFileActive _ TRUE; LongStorage.FreeString[pressFileName]; pressFileName _ LongStorage.CopyString[name]; END; FinishFile: PROCEDURE = BEGIN aborted: BOOLEAN _ FALSE; lastPage: CARDINAL; index: LONG CARDINAL; IF ~pressFileActive THEN RETURN; Press.Finish[]; index _ Streams.GetIndex[outputStream]; lastPage _ Inline.LongDivMod[index, bytesPerPage].quotient; IF transmitting THEN BEGIN OPEN PressUtilities; out.Put[rope["sending to "], string[printerName], rope["..."]]; FileStream.SetLength[outputStream, index]; Streams.SetIndex[outputStream, 0]; out.Flush[]; IF AbortRequested[] THEN SIGNAL Abort; SendPressStream[ outputStream, lastPage, printerName, cParameters.copies, PropList, pressFileName ! ServerBusy => {Wait["busy", 8]; RESUME}; ServerTimeout => {Wait["not responding", 0]; RESUME}; ServerTrouble => { IF message # NIL THEN {out.Put[string[message]]; out.Flush[];}; aborted _ TRUE; CONTINUE}]; END; IF outputFile # NIL THEN { FileStream.SetLength[outputStream, Streams.GetIndex[outputStream]]; Streams.Destroy[outputStream]; outputStream _ NIL}; out.PutRope[IF aborted THEN "...Aborted\n" ELSE "Done\n"]; out.Flush[]; pressFileActive _ FALSE; END; ComputeLineWidth: PROCEDURE [p: PrintOps.ParametersHandle] RETURNS [width: Mica] = BEGIN SELECT p.mode FROM portrait => width _ Press.pageWidth - p.margins[right] - p.margins[left]; landscape => width _ Press.pageHeight - p.margins[top] - p.margins[bottom]; ENDCASE => ERROR; width _ width - (p.columns - 1)*(p.betweenColumns); width _ LOOPHOLE[width, CARDINAL]/p.columns; RETURN END; neededFFs: CARDINAL; bufferPages: CARDINAL = 10; bufferWords: CARDINAL = bufferPages * Environment.wordsPerPage; bufferChars: CARDINAL = bufferWords * charsPerWord; PrintFile: PROCEDURE [fh: Segments.FHandle] RETURNS [lastPage: CARDINAL] = BEGIN OPEN Streams; s: Handle _ CreateStream[fh, Read]; iBufIndex: CARDINAL _ 0; buffer: RECORD [ numChars: CARDINAL, p: LONG POINTER TO PACKED ARRAY OF CHARACTER]; procs: PrintOps.PressProcsObject _ [ Press.Character, Press.GetWidthOfCharacter, Press.PieceOfLine, Press.SetCurrentFont, Press.SkipSomeSpace, Press.SetCurrentPosition, Press.GetCurrentPosition, Press.GetCurrentPageNumber, Press.SetCurrentPageNumber, Press.GetHeightOfFont]; Cleanup: PROCEDURE = {Streams.Destroy[s]; LongStorage.FreePages[buffer.p]}; NextChar: PROCEDURE RETURNS [c: CHARACTER] = BEGIN OPEN Streams; IF iBufIndex = buffer.numChars THEN { IF AbortRequested[] THEN SIGNAL Abort; buffer.numChars _ GetBlock[ s, buffer.p, bufferWords] * charsPerWord; IF buffer.numChars = 0 THEN {iBufIndex _ 0--NOTE PDR--; ERROR PrintOps.DataEnd}; IF GetIndex[s] MOD 2 # 0 THEN buffer.numChars _ buffer.numChars - 1; iBufIndex _ 0}; c _ buffer.p[iBufIndex]; iBufIndex _ iBufIndex + 1; RETURN END; buffer.p _ LongStorage.Pages[bufferPages]; buffer.numChars _ 0; lastPage _ PrintOps.Format[NextChar, @procs, @cParameters ! UNWIND => Cleanup[]]; Cleanup[]; BEGIN s: CARDINAL = IF sides = 2 THEN 2 ELSE 1; neededFFs _ (cParameters.columns*s) - ((lastPage - 1) MOD (cParameters.columns*s)); END; RETURN END; PressMail: PROCEDURE [file: STRING] = BEGIN ENABLE BEGIN MailFile.Error => { IF code = fileNotFound THEN { out.Put[rope[" Can't find "], string[file], char['\n]]; out.Flush[]; CONTINUE} ELSE {AbortFile["Mail file problem"]; IF ~debugging THEN CONTINUE}}; Segments.FileNameProblem[] => {out.Put[rope[" Can't find "], string[name], char['\n]]; out.Flush[]; CONTINUE}; Press.BadParameters => {AbortFile["Bad parameters"]; IF ~debugging THEN CONTINUE}; Press.InternalError => {AbortFile["Internal Error"]; IF ~debugging THEN CONTINUE}; Press.PartBufferOverflow => {AbortFile["Document too complicated"]; IF ~debugging THEN CONTINUE}; END; header: STRING _ [60]; uName: STRING _ [60]; fh: Segments.FHandle; mH: MailFile.Handle; createTime: Time.Packed; IF transmitting AND ~haveStatus AND ~PrintOps.GetStatus[] THEN BEGIN IF controllingExec # NIL THEN { execIn: IO.STREAM = controllingExec.in; WHILE execIn.CharsAvail[] DO [] _ execIn.GetChar[] ENDLOOP; }; Segments.ReleaseFile[fh]; ERROR Abort; END; CheckForExtension[name: file, ext: ".mail"L]; fh _ Segments.NewFile[file]; createTime _ Segments.GetFileTimes[fh].create; haveStatus _ TRUE; String.AppendString[header, file]; String.AppendString[header, " "L]; Time.Append[header, Time.Unpack[createTime]]; Segments.ReleaseFile[fh]; IF pressFileActive AND outputFile = NIL AND (Streams.GetIndex[ outputStream] / bytesPerPage) > 200 THEN FinishFile[]; out.Put[rope["Pressing mail file "], string[file]]; ShowParameters[]; out.PutRope["..."]; out.Flush[]; uName.length _ 0; ConvertUnsafe.AppendRope[uName, UserCredentials.GetUserCredentials[].name]; mH _ MailFile.Create[file, uName]; Press.SetHeaderText[NIL, FALSE]; IF pressFileActive THEN THROUGH [0..neededFFs) DO Press.Character['\f]; Press.SetTrailerText[NIL, FALSE]; -- keep trailer on last page ENDLOOP; Press.SetCurrentPageNumber[1]; IF cParameters.headers THEN Press.SetHeaderText[header, TRUE]; IF cParameters.trailers THEN Press.SetTrailerText[header, TRUE]; BEGIN OPEN Press; pages: CARDINAL; IF fontChanged THEN InstallFont[font, TRUE]; SetMode[cParameters.columns, cParameters.betweenColumns, cParameters.mode]; SetMargins[ cParameters.margins[left], cParameters.margins[right], cParameters.margins[top], cParameters.margins[bottom]]; IF ~pressFileActive THEN StartFile[file]; SetCurrentFont[defaultFont, cParameters.weight, cParameters.slope]; SetCurrentTabWidth[GetWidthOfCharacter[' ]*cParameters.tab]; out.Put[card[pages _ PrintMailFile[mH]], rope[" page"]]; IF pages # 1 THEN out.PutChar['s]; END; out.PutChar['\n]; out.Flush[]; RETURN END; PrintMailFile: PROCEDURE [mH: MailFile.Handle] RETURNS [lastPage: CARDINAL] = BEGIN OPEN p: cParameters; nMessages: CARDINAL = MailFile.GetAttributes[mH, NIL].nMessages - 1; curMessage: CARDINAL _ 0; state: {toc, between, cr1, cr2, heading, cr3, message} _ toc; block: Environment.Block; first: BOOLEAN _ TRUE; procs: PrintOps.PressProcsObject _ [ Press.Character, Press.GetWidthOfCharacter, Press.PieceOfLine, Press.SetCurrentFont, Press.SkipSomeSpace, Press.SetCurrentPosition, Press.GetCurrentPosition, Press.GetCurrentPageNumber, Press.SetCurrentPageNumber, Press.GetHeightOfFont]; NextChar: PROCEDURE RETURNS [c: CHARACTER] = BEGIN PAC: TYPE = LONG POINTER TO PACKED ARRAY OF CHARACTER; DO IF block.startIndex = block.stopIndexPlusOne THEN { IF AbortRequested[] THEN SIGNAL Abort; SELECT state FROM toc => {state _ cr1; RETURN['\f]}; cr1 => {cParameters.wrap _ FALSE; state _ cr2; RETURN['\n]}; cr2 => { IF first THEN {curMessage _ 0; first _ FALSE} ELSE IF (curMessage _ curMessage + 1) = nMessages THEN ERROR PrintOps.DataEnd; state _ heading; RETURN['\n]}; heading => { state _ cr3; Press.SetCurrentFont[defaultFont+1, cParameters.weight, cParameters.slope]; block _ MailFile.TOCEntry[mH, curMessage]}; cr3 => {state _ message; RETURN['\n]}; ENDCASE => { state _ cr1; cParameters.wrap _ TRUE; Press.SetCurrentFont[defaultFont, cParameters.weight, cParameters.slope]; block _ MailFile.MsgBody[mH, curMessage]}} ELSE EXIT; ENDLOOP; c _ LOOPHOLE[block.blockPointer, PAC][block.startIndex]; block.startIndex _ block.startIndex + 1; RETURN END; cParameters.wrap _ FALSE; block _ MailFile.TOC[mH]; lastPage _ PrintOps.Format[NextChar, @procs, @cParameters ! UNWIND => MailFile.Destroy[mH]]; MailFile.Destroy[mH]; BEGIN s: CARDINAL = IF sides = 2 THEN 2 ELSE 1; neededFFs _ (p.columns*s) - ((lastPage - 1) MOD (p.columns*s)); END; RETURN END; PressCurrentSelection: PROC [source: Rope.ROPE] = BEGIN ENABLE BEGIN Press.BadParameters => {AbortFile["Bad parameters"]; IF ~debugging THEN CONTINUE}; Press.InternalError => {AbortFile["Internal Error"]; IF ~debugging THEN CONTINUE}; Press.PartBufferOverflow => {AbortFile["Document too complicated"]; IF ~debugging THEN CONTINUE}; END; IF pressFileActive AND outputFile = NIL AND (Streams.GetIndex[ outputStream] / bytesPerPage) > 200 THEN FinishFile[]; IF Rope.Length[source] = 0 THEN { out.PutRope["No valid selection"]; RETURN}; out.PutRope["Pressing current selection"]; ShowParameters[]; out.PutRope["..."]; out.Flush[]; Press.SetHeaderText[NIL, FALSE]; IF pressFileActive THEN THROUGH [0..neededFFs) DO Press.Character['\f]; Press.SetTrailerText[NIL, FALSE]; -- keep trailer on last page ENDLOOP; Press.SetCurrentPageNumber[1]; BEGIN OPEN Press; pages: CARDINAL; IF fontChanged THEN InstallFont[font]; SetMode[cParameters.columns, cParameters.betweenColumns, cParameters.mode]; SetMargins[ cParameters.margins[left], cParameters.margins[right], cParameters.margins[top], cParameters.margins[bottom]]; IF ~pressFileActive THEN StartFile["CurrentSelection"L]; SetCurrentFont[defaultFont, cParameters.weight, cParameters.slope]; SetCurrentTabWidth[GetWidthOfCharacter[' ]*cParameters.tab]; out.Put[card[pages _ PrintSelection[source]], rope[" page"]]; IF pages # 1 THEN out.PutChar['s]; END; out.PutChar['\n]; out.Flush[]; RETURN END; PrintSelection: PROCEDURE [source: Rope.ROPE] RETURNS [lastPage: CARDINAL] = BEGIN l: INT = Rope.Length[source]; index: CARDINAL _ 0; procs: PrintOps.PressProcsObject _ [ Press.Character, Press.GetWidthOfCharacter, Press.PieceOfLine, Press.SetCurrentFont, Press.SkipSomeSpace, Press.SetCurrentPosition, Press.GetCurrentPosition, Press.GetCurrentPageNumber, Press.SetCurrentPageNumber, Press.GetHeightOfFont]; NextChar: PROCEDURE RETURNS [c: CHARACTER] = BEGIN IF AbortRequested[] THEN SIGNAL Abort; IF index = l THEN ERROR PrintOps.DataEnd; c _ Rope.Fetch[source, index]; index _ index + 1; RETURN END; lastPage _ PrintOps.Format[NextChar, @procs, @cParameters]; BEGIN OPEN p: cParameters; s: CARDINAL = IF sides = 2 THEN 2 ELSE 1; neededFFs _ (p.columns*s) - ((lastPage - 1) MOD (p.columns*s)); END; RETURN END; CheckForExtension: PROCEDURE [name, ext: LONG STRING] = BEGIN FOR i: CARDINAL DECREASING IN [0..name.length) DO IF name[i] = '. THEN RETURN; ENDLOOP; LongString.AppendString[name, ext]; END; defaultFont: Press.FontIndex = 0; InstallFont: PROCEDURE [f: LONG STRING, mail: BOOLEAN _ FALSE] = BEGIN name: STRING _ [40]; b: BufferItem _ [0, f]; c: CHARACTER; size: Press.Points; FinishFile[]; DO c _ GetChar[@b]; IF c = NUL THEN EXIT; IF c IN ['0..'9] THEN BEGIN Backup[@b]; EXIT END; String.AppendChar[name, c]; ENDLOOP; size _ GetNumber[@b, 8]; cParameters.weight _ medium; cParameters.slope _ regular; UNTIL (c _ GetChar[@b]) = NUL DO IF c = 'b THEN cParameters.weight _ bold ELSE IF c = 'i THEN cParameters.slope _ italic; ENDLOOP; Press.FlushFontBuffers[]; Press.PutFontInTable[defaultFont, name, size]; Press.PutFontInTable[defaultFont+1, name, size+2]; fontChanged _ FALSE; RETURN END; Abort: SIGNAL = CODE; Wait: PROCEDURE [why: Rope.ROPE, howlong: CARDINAL] = BEGIN start: Time.Packed; out.Put[rope["\nServer "], rope[why], rope["...will retry...type CONTROL-DEL to abort"]]; out.Flush[]; start _ Time.Current[]; UNTIL Time.Current[] - start > howlong DO IF AbortRequested[] THEN SIGNAL Abort; Process.Yield[]; ENDLOOP; out.PutRope["..."]; out.Flush[]; END; fontChanged, fontSpecified: BOOLEAN; Defaults: TYPE = RECORD [ font: STRING, columns: CARDINAL, margins: PrintOps.Margins]; lDefault: Defaults = ["Gacha6", 2, [Inch*3/4, Inch/2, Inch/2, Inch/2]]; pDefault: Defaults = ["Gacha8", 1, [Inch*3/4, Inch*3/4, Inch*3/4, Inch*3/4]]; nonProgMargins: PrintOps.Margins = [Inch*7/6, Inch*7/6, Inch, Inch]; font, bufferFile, outputFile: LONG STRING _ NIL; printerName: PUBLIC LONG STRING _ NIL; haveStatus: BOOLEAN; cParameters, dParameters: PrintOps.Parameters; ShowParameters: PROCEDURE = BEGIN out.Put[char['/], char[IF cParameters.mode = landscape THEN 'l ELSE 'p], card[cParameters.columns]]; IF ~cParameters.headers THEN out.PutRope["~a"]; IF ~cParameters.trailers THEN out.PutRope["~z"]; IF sides = 1 OR sides = 2 THEN out.Put[char['s], card[sides]]; END; InitGlobalParameters: PROCEDURE = BEGIN OPEN PressUtilities; dMode: Press.Mode _ IF UserProfile.Boolean["Hardcopy.Landscape", TRUE] THEN landscape ELSE portrait; dColumns: CARDINAL _ UserProfile.Number[ "Hardcopy.Columns", IF dMode = landscape THEN lDefault.columns ELSE pDefault.columns]; dTab: CARDINAL _ UserProfile.Number["Hardcopy.Tab", 8]; fontSpecified _ FALSE; dParameters _ [copies: 1, tab: dTab, margins: IF dMode = landscape THEN lDefault.margins ELSE pDefault.margins, columns: dColumns, weight: medium, slope: regular, mode: dMode]; Press.Initialize[]; SetupHardCopyOptions[]; printerName _ LongStorage.CopyString[hardcopyHost]; font _ LongStorage.CopyString[ IF hardcopyFont # NIL AND hardcopyFont.length # 0 THEN hardcopyFont ELSE IF dMode = landscape THEN lDefault.font ELSE pDefault.font]; fontChanged _ TRUE; fontSpecified _ FALSE; bufferFile _ LongStorage.CopyString["Swatee"L]; outputFile _ NIL; END; SetGlobalParameters: PROCEDURE [b: Buffer] = BEGIN d: PrintOps.ParametersHandle = @dParameters; sense: BOOLEAN _ TRUE; sc: CHARACTER; UNTIL (sc _ GetChar[b]) = NUL DO SELECT sc FROM 'c => SetCopies[GetNumber[b, 1], d]; 't => SetTabWidth[GetNumber[b, 8], d]; 'l => SetLandscape[GetNumber[b, 2], d]; 'p => SetPortrait[GetNumber[b, 1], d]; 's => SetSides[GetNumber[b, 0], d]; 'm => SetMail[d]; 'n => SetNonProg[d]; 'd => SetDebugging[~debugging]; 'a => d.headers _ sense; 'z => d.trailers _ sense; '-, '~ => {sense _ FALSE; LOOP}; ENDCASE; sense _ TRUE; ENDLOOP; cParameters _ dParameters; END; InitCurrentParameters: PROCEDURE = BEGIN fontSpecified _ FALSE; cParameters _ dParameters; END; BufferItem: TYPE = RECORD [p: CARDINAL, s: LONG STRING]; Buffer: TYPE = POINTER TO BufferItem; GetChar: PROCEDURE [b: Buffer] RETURNS [c: CHARACTER] = BEGIN OPEN b; c _ NUL; IF p < s.length THEN BEGIN c _ s[p]; p _ p + 1; IF c IN ['A..'Z] THEN c _ LOOPHOLE[LOOPHOLE[c, CARDINAL] + 40B]; END; RETURN END; Backup: PROCEDURE [b: Buffer] = BEGIN IF b.p # 0 THEN b.p _ b.p - 1; END; GetNumber: PROCEDURE [b: Buffer, default: CARDINAL] RETURNS [v: CARDINAL] = BEGIN c: CHARACTER; usedefault: BOOLEAN _ TRUE; v _ 0; WHILE (c _ GetChar[b]) IN ['0..'9] DO usedefault _ FALSE; v _ v*10 + (c - 60C); ENDLOOP; IF c # NUL THEN Backup[b]; IF usedefault THEN RETURN[default]; END; ProcessItem: PROCEDURE [arg, switches: STRING, selection: Rope.ROPE] = BEGIN b: BufferItem _ [0, switches]; c: PrintOps.ParametersHandle = @cParameters; sc: CHARACTER; sense: BOOLEAN _ TRUE; mail: BOOLEAN _ FALSE; IF AbortRequested[] THEN SIGNAL Abort; UNTIL arg.length = 0 OR (sc _ GetChar[@b]) = NUL DO SELECT sc FROM 'f => {SetFont[arg, c]; fontSpecified _ TRUE; arg.length _ 0}; 'h => {SetHost[arg, c]; arg.length _ 0}; 'o => {SetOutputFile[arg, c]; arg.length _ 0}; 'c => {SetCopies[GetNumber[@b, 1], c]; SetCopies[c.copies, @dParameters]}; 't => SetTabWidth[GetNumber[@b, 8], c]; 'l => SetLandscape[GetNumber[@b, 2], c]; 'p => SetPortrait[GetNumber[@b, 1], c]; 's => SetSides[GetNumber[@b, 0], c]; 'n => SetNonProg[c]; 'm => SetMail[c]; 'd => SetDebugging[~debugging]; 'a => c.headers _ sense; 'z => c.trailers _ sense; '-, '~ => {sense _ FALSE; LOOP}; ENDCASE => {out.Put[rope["Unknown switch = "], char[sc], char['\n]]; out.Flush[]}; sense _ TRUE; ENDLOOP; IF arg.length = 0 THEN SetGlobalParameters[@b] ELSE BEGIN IF c.mail THEN PressMail[arg] ELSE PressThisFile[arg, selection]; InitCurrentParameters[]; END; RETURN END; GetToken: PROCEDURE [commandLine: Rope.ROPE, x: INT, token, switches: STRING] RETURNS [nextX: INT, found: BOOLEAN _ FALSE] = BEGIN s: STRING; c: CHARACTER; l: INT _ Rope.Length[commandLine]; token.length _ switches.length _ 0; s _ token; FOR nextX _ x, nextX + 1 WHILE nextX < l DO SELECT (c _ Rope.Fetch[commandLine, nextX]) FROM IO.SP => IF found THEN EXIT; '/ => s _ switches; '\n, '; => EXIT; ENDCASE => {found _ TRUE; String.AppendChar[s, c]}; ENDLOOP; RETURN END; Command: ENTRY PROCEDURE [param: Rope.ROPE, selection: Rope.ROPE _ NIL, cmd: Commander.Handle _ NIL] = BEGIN OPEN Streams, Segments; ENABLE UNWIND => {controllingExec _ NIL; out _ NIL}; x: INT _ 0; found: BOOLEAN; arg: STRING _ [40]; switches: STRING _ [20]; b: BufferItem _ [0, switches]; swatee: FHandle _ NewFile["Swatee"L, ReadWrite]; controllingExec _ cmd; out _ IF cmd = NIL THEN ViewerIO.CreateMessageWindowStream[] ELSE cmd.out; busy _ TRUE; Buttons.ReLabel[printButton, "AbortPrint"]; abortPlease _ FALSE; LockFile[swatee]; haveStatus _ FALSE; sides _ 0; transmitting _ TRUE; pressFileActive _ FALSE; pressFileName _ NIL; bufferStream _ NIL; outputStream _ NIL; neededFFs _ 0; InitGlobalParameters[]; SetGlobalParameters[@b]; InitCurrentParameters[]; DO [x, found] _ GetToken[param, x, arg, switches]; IF found THEN ProcessItem[arg, switches, selection ! Abort => {out.PutRope["..ABORTED\n"]; out.Flush[]; EXIT}] ELSE EXIT; ENDLOOP; FinishFile[! Abort => {out.PutRope["..ABORTED\n"]; out.Flush[]; CONTINUE}]; Press.Reset[]; IF bufferStream # NIL THEN {Streams.Destroy[bufferStream]; bufferStream _ NIL}; font _ LongStorage.FreeStringNil[font]; bufferFile _ LongStorage.FreeStringNil[bufferFile]; outputFile _ LongStorage.FreeStringNil[outputFile]; pressFileName _ LongStorage.FreeStringNil[pressFileName]; UnlockFile[swatee]; ReleaseFile[swatee]; Buttons.ReLabel[printButton, "PrintSelection"]; abortPlease _ FALSE; busy _ FALSE; controllingExec _ NIL; out _ NIL; RETURN END; AbortRequested: PROC RETURNS [BOOLEAN] = { IF abortPlease THEN RETURN [TRUE]; IF controllingExec # NIL THEN IF controllingExec.in.UserAbort THEN RETURN [TRUE]; RETURN [FALSE]; }; CVPrintProc: Buttons.ButtonProc = TRUSTED {IF busy THEN abortPlease _ TRUE ELSE Process.Detach[FORK Command["$$$", ViewerTools.GetSelectionContents[]]]; -- selection computed here because once print starts outputting characters to typescript, selection changes. }; CommandProc: Commander.CommandProc = TRUSTED BEGIN Command[cmd.commandLine, NIL, cmd]; END; Init: PROCEDURE = {Commander.Register["Print", CommandProc, "..for printing stuff"]; printButton _ Buttons.Create[info: [name: "PrintSelection"], proc: CVPrintProc]; }; Init[]; END... æPrintControl.mesa; edited by Johnsson on 17-Apr-81 9:14:29 edited by Paul Rovner on 8-Feb-82 10:20:52 edited by Warren Teitelman on March 8, 1983 2:41 pm edited by Michael Plass on May 2, 1983 4:39 pm edited by MBrown on July 2, 1982 4:10 pm Main body 23-Mar-82 11:47:04 Fixed PrintSelection to compute current selection before doing anything else. 17-Apr-82 20:50:16 removed reference to anExecHandle. June 18, 1982 12:04 pm converted to 3.2, IOSTREAM -> IO, change in call to Buttons.Create, make CommandProc be safe. July 2, 1982 4:10 pm by MBrown: Added Hardcopy.Tab. March 8, 1983 2:40 pm by Teitelman: controllingExec is now set each time a print operation is executed. This is to cover the case where printselection is used and the original exec that print was run in is now destroyed. PrintSelection now uses the default exec, and out is a dribblestream to that exec as well as to the messagewindow. May 2, 1983 4:10 pm by Plass: Converted to use Commander instead of UserExec. Ê£˜Jšœ;™;Jšœ*™*Jšœ4™4Jšœ.™.Jšœ(™(J˜J˜šÏk ˜ Jšœœ'˜4Jšœ œ!˜0Jšœœ˜!Jšœ œ3˜DJšœ œ ˜Jšœœ˜Jš œœœOœœ ˜sJšœ œ#˜3Jšœ œ;˜LJšœ œ:œ ˜Wšœœ˜ J˜EJ˜QJ˜IJ˜VJ˜\J˜;—šœœ˜J˜TJ˜?—šœ œ˜J˜MJ˜—Jšœœ˜Jšœœœ˜!šœ œ˜J˜T—šœœ˜J˜Jš˜Jš œœœ'œœ˜DJ˜J˜!Jšœœ˜Jš˜Jšœ˜J˜—šŸœ œœ!˜>Jš˜J˜#Jšœ œ˜Jšœœ˜šœœœ/˜KJ˜ —J˜$J˜(Jšœ œ˜Jš˜Jšœ˜J˜—šŸ œ œœ!˜DJšœœ˜J˜ J˜$Jšœœ˜J˜#šœœœ˜#Jš œ œœœœ˜LJšœœ3˜BJšœ˜—J˜'Jšœœ˜J˜2Jšœ ˜ Jš˜Jšœ˜J˜—šŸ œ œœ!˜EJš˜J˜Jšœœ˜1J˜J˜Jš˜Jšœ˜J˜—šŸ œ œœ!˜DJš˜J˜Jšœœ˜1J˜J˜Jšœ˜J˜—šŸ œ œ!˜6Jš˜Jšœ œ˜Jšœ œ˜J˜Jš˜šœœœ˜Jšœœœ˜'šœ˜Jšœœ˜!—J˜—Jšœ˜ Jšœ˜—Jšœ"œ$œ˜TJ˜J˜.Jšœ œ˜J˜"J˜#J˜-šœœœœ˜>Jšœ$œ˜6—J˜)J˜J˜J˜ J˜9šœ ˜Jš˜J˜*šœ˜Jšœœ˜#J˜+Jšœ œœ˜J˜?J˜ Jšœœœ˜&˜J˜JJšœ œ˜(Jšœ-œ˜5˜Jšœ œœ˜/J˜ Jšœ œ˜Jšœ˜ —Jšœ)˜/—Jšœ œ œ œ ˜7J˜ J˜Jš˜—JšœA˜EJš˜Jšœ˜—Jšœœœ˜ šœ˜šœ˜J˜Jšœœœž˜>Jšœ˜——J˜Jšœœœ˜>šœœœ˜@Jšœœ˜Jšœœ˜Jšœ œ˜&J˜K˜ J˜6J˜7—Jšœœ˜)J˜CJ˜Jš˜šœœœ˜Jšœœœ˜'šœ˜Jšœœ˜!—J˜—J˜Jšœ˜ Jšœ˜—J˜-J˜J˜.Jšœ œ˜J˜"J˜#J˜-J˜šœœœœ˜>Jšœ$œ˜6—J˜3J˜J˜Jšœ ˜ Jšœ˜J˜KJ˜"Jšœœœ˜ šœ˜šœ˜J˜Jšœœœž˜>Jšœ˜——J˜Jšœœœ˜>šœœœ˜@Jšœœ˜Jšœœ˜Jšœ œœ˜,J˜K˜ J˜6J˜7—Jšœœ˜)J˜CJ˜Jšœ$œ˜6—šœœ˜!Jšœ#œ˜+—J˜*J˜J˜Jšœ ˜ Jšœœœ˜ šœ˜šœ˜J˜Jšœœœž˜>Jšœ˜——˜Jšœœ˜Jšœœ˜Jšœ œ˜&J˜K˜ J˜6J˜7—Jšœœ ˜8J˜CJ˜J˜(J˜.J˜JJ˜'J˜(J˜'J˜$J˜J˜J˜J˜J˜Jšœœœ˜ JšœK˜R—Jšœœ˜ Jšœ˜—Jšœœ˜.Jš œœœœœ9œ˜jJš˜Jšœ˜J˜—š Ÿœ œœœœ˜MJšœ œ œœ˜.Jš˜Jšœœ˜ Jšœ œ˜ Jšœœ˜"J˜#J˜ šœœ ˜+šœ&˜0Jš œœœœœ˜J˜Jšœ œ˜Jšœ œ˜3—Jšœ˜—Jš˜Jšœ˜J˜——šŸœœ œœœœœ˜fšœœ˜šœœœœ˜4Jšœœ˜ ——Jšœœ˜Jšœœ˜Jšœ œ˜J˜J˜0Jšœ˜Jš œœœœ&œ ˜JJšœœ˜ J˜+Jšœœ˜J˜J˜Jšœ œ˜J˜ Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜J˜J˜J˜J˜š˜J˜/šœ˜Jšœ[œ˜eJšœœ˜ —Jšœ˜—Jšœ@œ˜KJ˜Jšœœœ0œ˜OJ˜'J˜3J˜3J˜9J˜J˜J˜J˜/Jšœœ˜Jšœœ˜ Jšœœœ˜!Jš˜Jšœ˜J˜šŸœœœœ˜*Jšœ œœœ˜"Jšœœœœœœœ˜QJšœœ˜Jšœ˜—J˜šœ"˜)š œœœœœœ6žl˜ÛJ˜J˜——šœ$˜$Jš˜Jš˜Jšœœ˜#Jšœ˜J˜—šŸœ œ˜šœB˜BJ˜P—J˜J˜—Jšœ ™ J˜J˜J˜Jšœ˜J˜J˜—J™`J™5J™Jšœ)œœ=™tJ™J™3J™J™ÏJ™J™M—…—j„Ž