<> <> <> <> <> <<>> 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. <<>> <> <> <> <<>>