DIRECTORY BasicTime, Convert, FS, IO, PDQueue, RefText, Rope; PDQueueImpl: MONITOR IMPORTS BasicTime, Convert, FS, IO, RefText, Rope EXPORTS PDQueue = BEGIN ROPE: TYPE ~ Rope.ROPE; Request: TYPE = PDQueue.Request; showTimes: BOOL _ TRUE; diskFileName: ROPE _ NIL; deferSaving: BOOLEAN _ FALSE; saveDeferred: BOOLEAN _ FALSE; RequestStatus: TYPE ~ PDQueue.RequestStatus; -- {notFound, canceled, waiting, printing} RequestQueue: TYPE ~ REF RequestQueueRep; RequestQueueRep: TYPE ~ RECORD [ next: RequestQueue _ NIL, number: CARDINAL _ 0, request: PDQueue.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: ENTRY 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 = 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["Reprint."]; action[[NIL, NIL, NIL, NIL, NIL, copies], NAT.LAST, abortCurrent ! ABORTED => {aborted _ TRUE; CONTINUE}]; LogMessage["Reprint completed."]; Save[]; } ELSE { 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]; Save[]; }; }; CancelRequest: PUBLIC ENTRY PROC [requestNumber: CARDINAL] RETURNS [ok: BOOLEAN] = { RemoveRequest[requestNumber]; Save[]; 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; TimeToRope: PROC [time: BasicTime.GMT _ BasicTime.nullGMT] RETURNS [r: ROPE] = BEGIN unpacked: BasicTime.Unpacked _ BasicTime.Unpack[(IF time = BasicTime.nullGMT THEN BasicTime.Now[] ELSE time)]; stream: IO.STREAM _ IO.ROS[]; 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]]; r _ IO.RopeFromROS[stream]; END; END. DPDQueueImpl.mesa Copyright (C) 1984, 1985, Xerox Corporation. All rights reserved. Michael Plass, April 10, 1985 5:28:48 pm PST Tim Diebert: February 27, 1986 8:53:59 am PST Requests are numbered modulo this number. Records the process using the disk under the monitor, to avoid deadlocks in case of disk errors. ΚΧ˜code™K™BK™,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˜KšœœΟc*˜XK˜Kšœœœ˜)šœœœ˜ Kšœœ˜Kšœœ˜Kš œœœœœœ˜8Kšœ"˜"—K˜Kšœœ˜Kšœ œ˜K™šΟnœœ˜Kšœ œœœ˜2Kšœœœœ˜"Kšœ$˜$Kšœœ˜Kšœ˜K˜—š   œœœœ˜LKš œœœœ#œ œ˜Jš˜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˜š   œœœœœ˜TKšœ1œœœ˜nKš œœœœœ˜Kšœ œ˜Kš œœœ"œœ˜yKšœœœœ˜jKšœœ˜Kšœ˜—K˜Kšœ˜——…—/ŠD₯