-- ReturnOp.mesa -- edited by Schroeder, January 18, 1981 3:06 PM -- edited by Brotz, August 15, 1980 5:48 PM -- edited by Levin, January 12, 1981 3:09 PM DIRECTORY crD: FROM "CoreDefs", exD: FROM "ExceptionDefs", gsD: FROM "GlobalStorageDefs", intCommon: FROM "IntCommon", mfD: FROM "MailFormatDefs", opD: FROM "OperationsDefs", ovD: FROM "OverviewDefs", vmD: FROM "VirtualMgrDefs"; ReturnOp: PROGRAM IMPORTS crD, exD, gsD, intC:intCommon, mfD, vmD EXPORTS opD SHARES opD = BEGIN fileAccessError: ERROR = CODE; -- Had error return trying to read or write a file ReturnMailFileOperation: PUBLIC PROCEDURE [buffer: POINTER TO opD.BufferRecord] RETURNS [ovD.ErrorCode] = BEGIN -- variables of ReturnMailFileOperation out: RECORD[ --output buffer ptr: POINTER TO UNSPECIFIED, --pointer to buffer start limit: CARDINAL, --size of buffer in bytes (a multiple of 512) byteCount: CARDINAL, --number of bytes to write out from the buffer firstPage: crD.PageNumber, --number of the first page in the buffer string: STRING, --a string overlayed on the buffer area isGSPage: BOOLEAN --buffer page was gotten from global storage division ] _ [NIL, , 0, , , FALSE]; in: RECORD[ --input buffer ptr: POINTER TO UNSPECIFIED, --pointer to buffer start limit: CARDINAL, --size of buffer in bytes (a multiple of 512) firstPage: crD.PageNumber, --number of the first page in the buffer firstByte: CARDINAL, --starting point for a copy string: STRING, --a string overlayed on the buffer area isGSPage: BOOLEAN --buffer page was gotten from global storage division ] _ [ , , , , , FALSE]; errorCode: ovD.ErrorCode; tOCEntry: vmD.TOCFixedPart; tb: vmD.TOCFixedPartPtr = @tOCEntry; stateOfPreviousEntry: {initialDeletions, deleted, notDeleted}; changingInPlace: BOOLEAN _ TRUE; --becomes FALSE when first deletion found replacePosition, --next place for ReplaceCharInOutBuffer to put character in output buffer i, p, b, appendCharCount, firstFree, eofByte, firstByteOfFirstDeletion: CARDINAL; eofPage, firstPageOfFirstDeletion: crD.PageNumber; tocValid: BOOLEAN _ TRUE; -- internal procedures of ReturnMailFileOperation AdvanceOutBufferPosition: PROCEDURE[page: crD.PageNumber, byte: CARDINAL] = BEGIN IF out.ptr = NIL THEN BEGIN -- need to set up the buffers buffer.s1 _ (buffer.s1 / 256) * 512; --normalize size to n*512 bytes buffer.s2 _ (buffer.s2 / 256) * 512; --normalize size to n*512 bytes IF buffer.s1 > buffer.s2 THEN {in.ptr _ buffer.b2; in.limit _ buffer.s2; out.ptr _ buffer.b1; out.limit _ buffer.s1} ELSE {in.ptr _ buffer.b1; in.limit _ buffer.s1; out.ptr _ buffer.b2; out.limit_ buffer.s2}; IF out.limit = 0 THEN -- larger buffer didn't contain a full page {out.ptr _ gsD.GetMemoryPages[1]; out.limit _ 512; out.isGSPage _ TRUE}; out.string _ LOOPHOLE[out.ptr - 2, STRING]; -- make sure that requested page doesn't appear to be in buffer out.firstPage _ page + 1; END; -- need to set up the buffers IF out.firstPage # page THEN BEGIN --desired page not in the output buffer IF out.byteCount # 0 THEN WriteOutputBuffer[]; IF byte # 0 OR changingInPlace THEN BEGIN [errorCode, out.byteCount] _ crD.ReadPages[out.ptr, 512, page, intC.mailFileHandle]; IF errorCode # ovD.ok THEN ERROR fileAccessError; END; out.firstPage _ page; END; IF changingInPlace THEN replacePosition _ byte ELSE out.byteCount _ byte; END; -- of AdvanceOutBufferPosition -- ReplaceCharInOutBuffer: PROCEDURE[c: CHARACTER] = BEGIN IF replacePosition >= 512 THEN BEGIN WriteOutputBuffer[]; out.firstPage _ out.firstPage + 1; replacePosition _ 0; [errorCode, out.byteCount] _ crD.ReadPages[out.ptr, 512, out.firstPage, intC.mailFileHandle]; IF errorCode # ovD.ok THEN ERROR fileAccessError; END; out.string[replacePosition] _ c; replacePosition _ replacePosition + 1; END; -- of ReplaceCharInOutBuffer -- AppendCharToOutBuffer: PROCEDURE[c: CHARACTER] = BEGIN IF out.byteCount >= out.limit THEN BEGIN WriteOutputBuffer[]; out.firstPage _ out.firstPage + out.limit / 512; out.byteCount _ 0; END; out.string[out.byteCount] _ c; out.byteCount _ out.byteCount + 1; appendCharCount _ appendCharCount + 1; END; -- of AppendCharToOutBuffer -- WriteOutputBuffer: PROCEDURE = BEGIN IF (errorCode _ crD.WritePages[out.ptr, out.byteCount, out.firstPage, intC.mailFileHandle]) # ovD.ok THEN ERROR fileAccessError; END; -- of WriteOutputBuffer -- SetUpInBufferAndIndicateCompactionUnderway: PROCEDURE = BEGIN --set up the input buffer IF in.limit = 0 THEN -- smaller buffer didn't contain a full page {in.ptr _ gsD.GetMemoryPages[1]; in.limit _ 512; in.isGSPage _ TRUE}; in.string _ LOOPHOLE[in.ptr - 2, STRING]; -- put compaction mark in toc vmD.SetTOCValidity[FALSE]; tocValid _ FALSE; END; --of SetUpInBufferAndIndicateCompactionUnderway-- CopyTo: PROCEDURE [page: crD.PageNumber, byte: CARDINAL] = BEGIN pagesLeft, index, firstCopyCount, byteCount: CARDINAL; --get page and byte of last byte to copy IF tocValid THEN exD.SysBug[]; -- make sure in buffer set up-- IF byte = 0 THEN {page _ page -1; byte _ 511} ELSE byte _ byte - 1; pagesLeft _ page - in.firstPage + 1; UNTIL pagesLeft = 0 DO --calculate number of bytes to read this time byteCount _ IF pagesLeft < in.limit / 512 THEN pagesLeft * 512 ELSE in.limit; --do the read [errorCode, ] _ crD.ReadPages[in.ptr, byteCount, in.firstPage, intC.mailFileHandle]; IF errorCode # ovD.ok THEN ERROR fileAccessError; --calculate pages left to read and first page of in buffer for next iteration in.firstPage _ in.firstPage + byteCount / 512; pagesLeft _ page - in.firstPage + 1; --set byteCount to be the number of bytes to copy for this iteration IF pagesLeft = 0 THEN byteCount _ byteCount - (511 - byte); byteCount _ byteCount - in.firstByte; --copy to the output buffer firstCopyCount _ MIN[byteCount, out.limit - out.byteCount]; FOR index IN [0 .. firstCopyCount) DO out.string[out.byteCount + index] _ in.string[in.firstByte + index]; ENDLOOP; IF (out.byteCount _ out.byteCount + firstCopyCount) >= out.limit THEN BEGIN WriteOutputBuffer[]; out.firstPage _ out.firstPage + out.limit / 512; out.byteCount _ byteCount - firstCopyCount; in.firstByte _ in.firstByte + firstCopyCount; FOR index IN [0 .. out.byteCount) DO out.string[index] _ in.string[in.firstByte + index]; ENDLOOP; END; in.firstByte _ 0; ENDLOOP; END; -- of CopyTo -- -- Code for ReturnMailFileOperation BEGIN -- block for EXITS and signals ENABLE fileAccessError => GOTO errorReturn; IF (firstFree _ vmD.GetFirstFreeTOCIndex[]) = 1 THEN BEGIN vmD.CleanupTOC[delete]; errorCode _ crD.DeleteFile[intC.mailFileHandle]; GOTO normalReturn; END; FOR i IN [vmD.GetFirstChangedTOCIndex[] .. firstFree) DO vmD.GetTOCFixedPart[i,tb]; --first argument should be of type TOCIndex IF tb.deleted THEN EXIT; IF tb.changed THEN BEGIN AdvanceOutBufferPosition[tb.firstPage, tb.firstByte]; mfD.CreateStamp[tb, ReplaceCharInOutBuffer]; END; REPEAT FINISHED => BEGIN -- no deleted entries were found, so we are done IF out.byteCount # 0 THEN WriteOutputBuffer[]; errorCode _ crD.CloseFile[intC.mailFileHandle]; vmD.CleanupTOC[resetChanges]; GOTO normalReturn; END; ENDLOOP; -- a deleted entry exists -- remember page and byte of last character before first deleted message firstPageOfFirstDeletion _ tb.firstPage; firstByteOfFirstDeletion _ tb.firstByte; stateOfPreviousEntry _ initialDeletions; changingInPlace _ FALSE; [errorCode, eofPage, eofByte] _ crD.UFileLength[intC.mailFileHandle]; IF errorCode # ovD.ok THEN GOTO errorReturn; -- process remaining messages in the toc; remember that message i is deleted FOR i IN (i .. firstFree + 1] DO SELECT i FROM < firstFree => vmD.GetTOCFixedPart[i, tb]; --get next entry from TOC = firstFree => BEGIN -- calculate distance, in pages and bytes, from last toc message to EOF b _ tb.firstByte + tb.offsetToHeader + tb.textLength; tb.firstPage _ tb.firstPage + (b / 512); tb.firstByte _ b MOD 512; -- now tb.firstPage and tb.firstByte show end of mailfile as described by the toc IF tb.firstByte = eofByte AND tb.firstPage = eofPage THEN -- no more to copy BEGIN IF stateOfPreviousEntry = notDeleted THEN CopyTo[tb.firstPage, tb.firstByte]; EXIT; END ELSE BEGIN -- more to copy because of a partial TOC --makeup entry describing message starting after last TOCed message tb.deleted _ FALSE; tb.changed _ FALSE; END; END; ENDCASE => -- > firstFree -- BEGIN --makeup an entry describing deleted message starting at old EOF for mailfile tb.firstPage _ eofPage; tb.firstByte _ eofByte; tb.deleted _ TRUE; END; IF tb.deleted THEN --this entry is deleted BEGIN IF stateOfPreviousEntry = notDeleted THEN {CopyTo[tb.firstPage, tb.firstByte]; stateOfPreviousEntry _ deleted} END ELSE BEGIN --this entry is not deleted IF tb.changed THEN --this entry has been changed BEGIN SELECT stateOfPreviousEntry FROM = notDeleted => CopyTo[tb.firstPage, tb.firstByte]; = deleted => NULL; ENDCASE -- = initialDeletions -- => BEGIN AdvanceOutBufferPosition[firstPageOfFirstDeletion, firstByteOfFirstDeletion]; SetUpInBufferAndIndicateCompactionUnderway[]; END; appendCharCount _ 0; mfD.CreateStamp[tb, AppendCharToOutBuffer]; -- record the copy starting point b _ tb.firstByte + appendCharCount; in.firstPage _ tb.firstPage + (b / 512); in.firstByte _ b MOD 512; END --this entry has been changed ELSE BEGIN --this entry has not been changed IF stateOfPreviousEntry # notDeleted THEN BEGIN -- = initialDeletions OR = deleted -- IF stateOfPreviousEntry = initialDeletions THEN BEGIN AdvanceOutBufferPosition[firstPageOfFirstDeletion, firstByteOfFirstDeletion]; SetUpInBufferAndIndicateCompactionUnderway[]; END; -- record the copy starting point in.firstPage _ tb.firstPage; in.firstByte _ tb.firstByte; END; END; --this entry has not been changed stateOfPreviousEntry _ notDeleted; END; --this entry is not deleted ENDLOOP; IF stateOfPreviousEntry = initialDeletions THEN --new EOF is start of first deletion {p _ firstPageOfFirstDeletion; b _ firstByteOfFirstDeletion} ELSE --new EOF is end of last copy {p _ out.firstPage + out.byteCount / 512; b _ out.byteCount MOD 512}; IF p # 0 OR b # 0 THEN -- something is left BEGIN IF out.byteCount # 0 THEN WriteOutputBuffer[]; errorCode _ crD.UFileTruncate[p, b, intC.mailFileHandle]; IF errorCode # ovD.ok THEN GOTO errorReturn; errorCode _ crD.CloseFile[intC.mailFileHandle]; IF NOT tocValid THEN vmD.SetTOCValidity[TRUE]; vmD.CleanupTOC[resetChanges]; END ELSE -- whole file was deleted {errorCode _ crD.DeleteFile[intC.mailFileHandle]; vmD.CleanupTOC[delete]}; EXITS normalReturn => NULL; errorReturn => {[] _ crD.CloseFile[intC.mailFileHandle]; vmD.CleanupTOC[dontResetChanges]}; END; -- of EXITS block IF out.isGSPage THEN gsD.ReturnMemoryPages[1, out.ptr]; IF in.isGSPage THEN gsD.ReturnMemoryPages[1, in.ptr]; intC.mailFileHandle _ NIL; RETURN[errorCode]; END; -- of ReturnMailFileOperation -- END. -- of ReturnOp --z20461(529)\f1