DIRECTORY BasicTime, FS, IO, Convert, RefText, IPPrinterQueue, Rope; IPPrinterQueueImpl: MONITOR IMPORTS BasicTime, FS, IO, Rope, Convert, RefText EXPORTS IPPrinterQueue = BEGIN ROPE: TYPE ~ Rope.ROPE; Request: TYPE = IPPrinterQueue.Request; showTimes: BOOL _ TRUE; diskFileName: ROPE _ NIL; deferSaving: BOOLEAN _ FALSE; saveDeferred: BOOLEAN _ FALSE; RequestStatus: TYPE ~ IPPrinterQueue.RequestStatus; -- {notFound, canceled, waiting, printing} RequestQueue: TYPE ~ REF RequestQueueRep; RequestQueueRep: TYPE ~ RECORD [ next: RequestQueue _ NIL, number: CARDINAL _ 0, request: IPPrinterQueue.Request _ [NIL, NIL, NIL, NIL, NIL, 0], status: RequestStatus _ notFound]; queueHead: RequestQueue _ NIL; reqNumber: CARDINAL _ 0; Save: PROC = { IF deferSaving THEN {saveDeferred _ TRUE; RETURN}; IF diskFileName = NIL THEN RETURN; DumpToDisk[diskFileName, queueHead]; saveDeferred _ FALSE; }; DumpToDisk: PROC [diskFileName: ROPE, queueHead: RequestQueue] = BEGIN s: IO.STREAM _ FS.StreamOpen[diskFileName, create ! FS.Error => GOTO Out]; DO ENABLE FS.Error => EXIT; IF queueHead = NIL THEN EXIT; IO.PutF1[s, "%g ", IO.int[queueHead.number]]; IO.PutF1[s, "\"%g\" ", IO.rope[queueHead.request.fileName]]; IO.PutF1[s, "\"%g\" ", IO.rope[queueHead.request.requestTime]]; IO.PutF1[s, "\"%g\" ", IO.rope[queueHead.request.requestor]]; IO.PutF1[s, "\"%g\" ", IO.rope[queueHead.request.requestorPassword]]; IO.PutF1[s, "\"%g\" ", IO.rope[queueHead.request.separator]]; IO.PutF1[s, "%g ", IO.card[queueHead.request.copies]]; SELECT queueHead.status FROM notFound => IO.PutRope[s, "notFound\n"]; canceled => IO.PutRope[s, "canceled\n"]; waiting => IO.PutRope[s, "waiting\n"]; printing => IO.PutRope[s, "printing\n"]; ENDCASE => ERROR; queueHead _ queueHead.next; ENDLOOP; IO.Close[s ! FS.Error => GOTO Out]; EXITS Out => RETURN; END; Restore: PROC = { IF diskFileName = NIL THEN RETURN; queueHead _ LoadFromDisk[diskFileName]; }; LoadFromDisk: PROC [diskFileName: ROPE] RETURNS [queueHead: RequestQueue _ NIL] = BEGIN s: IO.STREAM _ FS.StreamOpen[diskFileName, create ! FS.Error => GOTO Out]; r: CARDINAL; rope: ROPE; tail: RequestQueue _ NIL; DO ENABLE FS.Error => EXIT; r _ IO.GetCard[s ! IO.EndOfStream => EXIT]; IF tail = NIL THEN queueHead _ tail _ NEW[RequestQueueRep] ELSE {tail.next _ NEW[RequestQueueRep]; tail _ tail.next}; tail.number _ r; tail.request.fileName _ IO.GetRopeLiteral[s ! IO.EndOfStream => GOTO Out]; tail.request.requestTime _ IO.GetRopeLiteral[s ! IO.EndOfStream => GOTO Out]; tail.request.requestor _ IO.GetRopeLiteral[s ! IO.EndOfStream => GOTO Out]; tail.request.requestorPassword _ IO.GetRopeLiteral[s ! IO.EndOfStream => GOTO Out]; tail.request.separator _ IO.GetRopeLiteral[s ! IO.EndOfStream => GOTO Out]; tail.request.copies _ IO.GetCard[s ! IO.EndOfStream => GOTO Out]; rope _ IO.GetTokenRope[s ! IO.EndOfStream => GOTO Out].token; tail.status _ SELECT TRUE FROM Rope.Equal[rope, "notFound", FALSE] => notFound, Rope.Equal[rope, "canceled", FALSE] => canceled, Rope.Equal[rope, "waiting", FALSE] => waiting, Rope.Equal[rope, "printing", FALSE] => printing, ENDCASE => ERROR; ENDLOOP; reqNumber _ r; IO.Close[s ! FS.Error => GOTO Out]; EXITS Out => RETURN [NIL]; END; InternalReset: INTERNAL PROC = { queueHead _ NIL; }; Reset: PUBLIC ENTRY PROC = {InternalReset[]; Save[]}; newRequest: CONDITION; requestLimit: CARDINAL _ 1000; QueueRequest: PUBLIC ENTRY PROC [request: Request] RETURNS [requestNumber: INT] = { ENABLE UNWIND => NULL; tail: RequestQueue; msg: ROPE; IF queueHead = NIL THEN Restore[]; tail _ queueHead; IF tail = NIL THEN tail _ queueHead _ NEW[RequestQueueRep] ELSE { DO IF tail.next = NIL THEN EXIT; tail _ tail.next; ENDLOOP; tail.next _ NEW[RequestQueueRep]; tail _ tail.next; }; requestNumber _ reqNumber _ tail.number _ (reqNumber + 1) MOD requestLimit; tail.request _ request; tail.status _ waiting; msg _ request.fileName; IF request.copies # 1 THEN msg _ IO.PutFR["%g (%g copies)", IO.rope[msg], IO.card[request.copies]]; InternalLogMessage[msg, requestNumber, request.requestor]; Save[]; NOTIFY newRequest; }; LogMessage: PUBLIC ENTRY PROC [message: ROPE, requestNumber: INT _ -1, userName: ROPE _ NIL, printCR: BOOL _ TRUE] = { InternalLogMessage[message, requestNumber, userName, printCR]; }; reprintCopies: CARDINAL _ 0; reprintCancelled: BOOLEAN _ FALSE; Reprint: PUBLIC ENTRY PROC [copies: CARDINAL] = { reprintCancelled _ FALSE; reprintCopies _ reprintCopies + copies; NOTIFY newRequest; }; CancelReprint: PUBLIC ENTRY PROC = { reprintCancelled _ TRUE; reprintCopies _ 0; }; ReprintCancelled: PUBLIC PROC RETURNS [BOOLEAN] = {RETURN [reprintCancelled]}; printingSuspended: BOOLEAN _ FALSE; GetSuspended: PUBLIC ENTRY PROC RETURNS [BOOLEAN] = {RETURN [printingSuspended]}; SetSuspended: PUBLIC ENTRY PROC [suspended: BOOLEAN] RETURNS [old: BOOLEAN] = { old _ printingSuspended; printingSuspended _ suspended; NOTIFY newRequest; }; abortCurrent: REF BOOL _ NEW[BOOL _ FALSE]; FindRequest: PROC [requestNumber: CARDINAL] RETURNS [request: Request, status: RequestStatus] = { ENABLE UNWIND => NULL; tail: RequestQueue; IF queueHead = NIL THEN Restore[]; tail _ queueHead; DO IF tail = NIL THEN EXIT; IF tail.number = requestNumber THEN RETURN [tail.request, tail.status]; tail _ tail.next; ENDLOOP; RETURN [[NIL, NIL, NIL, NIL, NIL, 0], notFound]; }; GetFirstRequest: ENTRY PROC [] RETURNS [requestNumber: INT, copies: CARDINAL, request: Request] = { ENABLE UNWIND => NULL; tail: RequestQueue; IF queueHead = NIL THEN Restore[]; tail _ queueHead; WHILE printingSuspended OR (queueHead = NIL AND reprintCopies = 0) DO WAIT newRequest ENDLOOP; abortCurrent^ _ FALSE; reprintCancelled _ FALSE; IF reprintCopies # 0 THEN { requestNumber _ -1; copies _ reprintCopies; reprintCopies _ 0; RETURN[requestNumber, copies, [NIL, NIL, NIL, NIL, NIL, copies]]; }; tail _ queueHead; IF tail = NIL THEN ERROR; RETURN [tail.number, tail.request.copies, tail.request]; }; RemoveRequest: ENTRY PROC [requestNumber: CARDINAL] = { ENABLE UNWIND => NULL; tail, oldTail: RequestQueue; tail _ queueHead; oldTail _ queueHead; IF queueHead = NIL THEN Restore[]; tail _ queueHead; DO IF tail = NIL THEN EXIT; IF tail.number = requestNumber THEN { IF tail.status = printing THEN abortCurrent^ _ TRUE; IF tail = queueHead THEN queueHead _ tail.next ELSE oldTail.next _ tail.next; EXIT; }; oldTail _ tail; tail _ tail.next; ENDLOOP; Save[]; }; SetStatus: ENTRY PROC [requestNumber: CARDINAL, status: RequestStatus] RETURNS [ok: BOOL] = BEGIN tail: RequestQueue; IF queueHead = NIL THEN Restore[]; tail _ queueHead; DO IF tail = NIL THEN EXIT; IF tail.number = requestNumber THEN {tail.status _ status; RETURN[TRUE]}; tail _ tail.next; ENDLOOP; RETURN [FALSE]; END; DeferSaving: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; deferSaving _ TRUE; }; DoDeferredSave: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; deferSaving _ FALSE; IF saveDeferred THEN Save[]; }; DoRequest: PUBLIC PROC [action: PROC [request: Request, requestNumber: CARDINAL, abort: REF BOOLEAN]] = { request: Request; requestNumber: INT; copies: CARDINAL; aborted: BOOL _ FALSE; [requestNumber, copies, request] _ GetFirstRequest[]; IF requestNumber >= 0 THEN { LogMessage["Started.", requestNumber, request.requestor]; []_ SetStatus[requestNumber, printing]; action[request, requestNumber, abortCurrent ! ABORTED => {aborted _ TRUE; CONTINUE}]; IF aborted THEN LogMessage["Aborted.", requestNumber, request.requestor] ELSE LogMessage["Completed.", requestNumber, request.requestor]; RemoveRequest[requestNumber]; }; }; CancelRequest: PUBLIC PROC [requestNumber: CARDINAL] RETURNS [ok: BOOLEAN] = { RemoveRequest[requestNumber]; RETURN [TRUE]; }; CheckRequest: PUBLIC PROC [requestNumber: CARDINAL, action: PROC [request: Request, status: RequestStatus]] = { status: RequestStatus _ notFound; request: Request; [request: request, status: status] _ FindRequest[requestNumber]; action[[request.fileName, request.requestTime, request.requestor, request.requestorPassword, request.separator, request.copies], status]; }; CountRequests: PUBLIC ENTRY PROC RETURNS [requestCount: NAT] = { tail: RequestQueue _ queueHead; IF queueHead = NIL THEN Restore[]; tail _ queueHead; requestCount _ 0; DO IF tail = NIL THEN EXIT; requestCount _ requestCount + 1; tail _ tail.next; ENDLOOP; }; EnumerateRequests: PUBLIC ENTRY PROC [action: PROC [requestNumber: CARDINAL, request: Request, status: RequestStatus] RETURNS [continue: BOOLEAN]] = { tail: RequestQueue _ NIL; requestNumber: CARDINAL; IF queueHead = NIL THEN Restore[]; tail _ queueHead; DO continue: BOOLEAN _ TRUE; myAction: PROC [request: Request, status: RequestStatus] = { IF status = printing OR status = waiting THEN continue _ action[requestNumber, request, status]; }; IF tail = NIL THEN EXIT; CheckRequest[(requestNumber _ tail.number), myAction]; IF NOT continue THEN EXIT; tail _ tail.next; ENDLOOP; }; RegisterDisk: PUBLIC ENTRY PROC [file: ROPE _ NIL] = {diskFileName _ file}; usingDisk: PROCESS _ NIL; MsgList: TYPE ~ REF MsgListRep; MsgListRep: TYPE ~ RECORD [ next: MsgList _ NIL, msg: ROPE _ NIL]; msgHead: MsgList _ NIL; msgTail: MsgList _ NIL; msgCnt: CARDINAL _ 0; InternalLogMessage: INTERNAL PROC [message: ROPE, requestNumber: INT _ -1, userName: ROPE _ NIL, printCR: BOOL _ TRUE] = { scratch: REF TEXT ~ RefText.ObtainScratch[100]; text: REF TEXT _ scratch; msg: ROPE _ NIL; IF msgHead = NIL THEN msgHead _ msgTail _ NEW[MsgListRep] ELSE {msgTail.next _ NEW[MsgListRep]; msgTail _ msgTail.next}; IF showTimes THEN { text _ TimeToRefText[BasicTime.Now[], text]; }; text _ RefText.AppendChar[text, ' ]; IF requestNumber >= 0 THEN { text _ RefText.AppendChar[text, 'R]; text _ RefText.AppendChar[text, '#]; text _ Convert.AppendInt[to: text, from: requestNumber]; text _ RefText.AppendChar[text, ' ]; }; text _ RefText.AppendChar[text, '\t]; text _ RefText.AppendRope[text, userName]; text _ RefText.AppendChar[text, '\t]; text _ RefText.AppendRope[text, message]; IF printCR OR showTimes THEN { text _ RefText.AppendChar[text, '\n]; }; msg _ Rope.FromRefText[text]; msgTail.msg _ msg; msgCnt _ msgCnt + 1; IF serverStream # NIL THEN {IO.PutRope[serverStream, msg]; IO.Flush[serverStream]}; IF msgCnt > 150 THEN BEGIN IF msgHead.next = NIL THEN {msgCnt _ 1; RETURN}; msgCnt _ msgCnt - 1; msgHead _ msgHead.next; END; RefText.ReleaseScratch[scratch]; }; monthName: ARRAY BasicTime.MonthOfYear OF Rope.ROPE ~ ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???"]; TimeToRefText: PROC [time: BasicTime.GMT _ BasicTime.nullGMT, text: REF TEXT] RETURNS [t: REF TEXT] = BEGIN unpacked: BasicTime.Unpacked _ BasicTime.Unpack[(IF time = BasicTime.nullGMT THEN BasicTime.Now[] ELSE time)]; stream: IO.STREAM _ IO.TOS[text]; zoneChar: CHAR _ ' ; IO.PutF[stream, "%2g-%g-%02g ", IO.int[unpacked.day], IO.rope[monthName[unpacked.month]], IO.int[unpacked.year MOD 100]]; IO.PutF[stream, "%2g:%02g:%02g", IO.int[unpacked.hour], IO.int[unpacked.minute], IO.int[unpacked.second]]; t _ IO.TextFromTOS[stream]; END; loggingMessages: BOOLEAN _ FALSE; serverStream: IO.STREAM _ NIL; RegisterTTY: PUBLIC ENTRY PROC [stream: IO.STREAM] = {serverStream _ stream}; SetLogState: PUBLIC ENTRY PROC [logging: BOOLEAN] RETURNS [old: BOOLEAN] = { old _ loggingMessages; loggingMessages _ logging; }; EnumerateMessages: PUBLIC PROC [action: PROC[message: ROPE] RETURNS [continue: BOOLEAN]] = BEGIN myTail: MsgList _ msgHead; DO IF myTail = NIL THEN RETURN; IF NOT action[myTail.msg] THEN RETURN; myTail _ myTail.next; ENDLOOP; END; END. όIPPrinterQueueImpl.mesa Copyright (C) 1984, 1985, Xerox Corporation. All rights reserved. Michael Plass, April 10, 1985 5:28:48 pm PST Tim Diebert: July 25, 1986 9:16:20 am PDT Rick Beach, December 13, 1985 12:55:29 pm PST Requests are numbered modulo this number. Records the process using the disk under the monitor, to avoid deadlocks in case of disk errors. CHANGE LOG Rick Beach, December 4, 1985 8:12:06 pm PST changes to: RemoveRequest fixed incorrect removal of request at head of queue Κ&˜codešœ™K™BK™,K™)K™-—K™šΟk ˜ Kšœ ˜ Kšœ˜Kšœ˜K˜Kšœ˜Kšœ˜—K˜KšΠlnœ˜Kšœ œœ˜1Kšœ˜šœ˜K˜Kšœœœ˜K˜šœ œ˜'K˜—Kšœ œœ˜K˜šœœœ˜K˜—Kšœ œœ˜Kšœœœ˜K˜Kšœœ"Οc*˜_K˜Kšœœœ˜)šœœœ˜ Kšœœ˜Kšœœ˜Kš œ#œœœœœ˜?Kšœ"˜"—K˜Kšœœ˜Kšœ œ˜K™šΟnœœ˜Kšœ œœœ˜2Kšœœœœ˜"Kšœ$˜$Kšœœ˜Kšœ˜K˜—š  œœœ˜FKš œœœœ#œ œ˜Jš˜Kšœœ œ˜Kšœ œœœ˜Kšœœ˜-Kšœœ#˜˜>Kšœ˜J˜—Kšœœ˜šœœœ˜"K˜—š  œœœœ œ˜1Kšœœ˜Kšœ'˜'Kšœ ˜Kšœ˜K˜—š  œœœœ˜$Kšœœ˜Kšœ˜Kšœ˜K˜—š  œœœœœœ˜NK˜—šœœœ˜#K™—Kš  œœœœœœœ˜Qš  œœœœ œœœ˜OKšœ˜Kšœ˜Kšœ ˜Kšœ˜K˜—š œœœœœœ˜+K™—š  œœœœ.˜aKšœœœ˜Kšœ˜Kšœ œœ ˜"Kšœ˜š˜Kšœœœœ˜Kšœœœ˜GK˜Kšœ˜—Kš œœœœœœ˜0Kšœ˜K˜—š  œœœœœ œ˜cKšœœœ˜Kšœ˜Kšœ œœ ˜"Kšœ˜Jšœœœœœœ œ˜^Jšœœ˜Jšœœ˜šœœ˜Jšœ˜Jšœ˜Jšœ˜Jš œœœœœœ ˜AJšœ˜—Kšœ˜Kšœœœœ˜Kšœ2˜8Kšœ˜K˜—š  œœœœ˜7Kšœœœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ œœ ˜"Kšœ˜š˜Kšœœœœ˜šœœ˜%Kšœœœ˜4Kšœœœ˜MKšœ˜Kšœ˜—K˜K˜Kšœ˜—Kšœ˜Kšœ˜K˜—š   œœœœœœ˜aKšœ˜Kšœ œœ ˜"Kšœ˜š˜Kšœœœœ˜Kšœœœœ˜IK˜Kšœ˜—Kšœœ˜Kšœ˜K˜—š  œœœœ˜"Kšœœœ˜Kšœœ˜Kšœ˜K˜—š œœœœ˜%Kšœœœ˜Kšœœ˜Kšœœ˜Kšœ˜K˜—š  œœœ œ#œ œœ˜iKšœ˜Kšœœ˜Kšœœ˜Kšœ œœ˜Kšœ5˜5šœœ˜Kšœ9˜9Kšœ'˜'Kšœ.œœœ˜UKšœ œ9˜HKšœ<˜@Kšœ˜Kšœ˜—Kšœ˜K˜—š   œœœœœœ˜NKšœ˜Kšœœ˜Kšœ˜K˜—š   œœœœ œ/˜oKšœ!˜!Kšœ˜Kšœ@˜@Kšœ‰˜‰Kšœ˜K˜—š   œœœœœœ˜@Kšœ˜Kšœ œœ ˜"Kšœ˜Kšœ˜š˜Kšœœœœ˜Kšœ ˜ K˜Kšœ˜—Kšœ˜K˜—š œœœœ œœ+œ œ˜–Kšœœ˜Kšœœ˜Kšœ œœ ˜"Kšœ˜š˜Kšœ œœ˜šœ œ.˜—•StartOfExpansionΓ[to: REF TEXT, from: GMT, start: Convert.TimePrecision _ years, end: Convert.TimePrecision _ minutes, includeDayOfWeek: BOOL _ FALSE, useAMPM: BOOL _ TRUE, includeZone: BOOL _ TRUE]šœ œ˜Kšœ,˜,Kšœ˜—Kšœ$˜$šœœ˜Kšœ$˜$Kšœ$˜$K–R[to: REF TEXT, from: INT, base: Convert.Base _ 10, showRadix: BOOL _ TRUE]šœ8˜8Kšœ$˜$Kšœ˜—Kšœ%˜%Kšœ*˜*Kšœ%˜%Kšœ)˜)šœ œ œ˜Kšœ%˜%Kšœ˜—Kšœ˜Kšœ'˜'Kš œœœœœ˜Sšœœ˜Kšœœœœ˜0Kšœ˜Kšœ˜Kšœ˜—Kšœ ˜ Kšœ˜—K˜šœ œœœ_˜’K˜—š  œœœœœœœœ˜kKšœ1œœœ˜nKš œœœœœ˜!Kšœ œ˜Kš œœœ"œœ˜yKšœœœœ˜jKšœœ˜Kšœ˜—K˜Kšœœœ˜!Kšœœœœ˜K˜š   œœœœ œœ˜MK˜—š  œœœœ œœœ˜LKšœ˜Kšœ˜Kšœ˜K˜—š œœœ œ œœ œ˜`Kšœ˜š˜Kšœ œœœ˜Kšœœœœ˜&Kšœ˜Kšœ˜—Kšœ˜——K˜Kšœ˜K™šœ™ ™+Kšœ Οr œ4™M——K™—…—-B>