-- RecipientList.mesa -- Edited by Levin, October 16, 1980 5:07 PM -- Edited by Schroeder, November 19, 1980 11:00 AM -- Edited by Brotz, November 12, 1981 3:02 PM DIRECTORY Inline USING [BITOR, BITXOR], LaurelSendDefs USING [], Storage USING [FreePages, FreeString, Pages, String], vmD: FROM "VirtualMgrDefs" USING [AllocateComposedMessageObject, CharIndex, ComposedMessagePtr, FreeVirtualMessageObject, GetMessageChar, GetMessageSize, InitComposedMessage, InsertMessageChar, StartMessageInsertion, StopMessageInsertion]; RecipientList: PROGRAM IMPORTS Inline, Storage, vmD EXPORTS LaurelSendDefs = BEGIN -- Declarations for recipient list data structures pageSize: CARDINAL = 256; Byte: TYPE = [0 .. 255]; Recipient: TYPE = RECORD [index: vmD.CharIndex, link: RecipientHandle]; RecipientHandle: TYPE = POINTER TO Recipient; maxOverflow: CARDINAL = (pageSize - pointerSize) / SIZE[Recipient]; pointerSize: CARDINAL = 1; -- hack: SIZE[Overflow] doesn't work maxBins: CARDINAL = 119; -- assumed to be less than maxOverflow BinNumber: TYPE = [0 .. maxBins); OverflowSlot: TYPE = [0 .. maxOverflow); Bins: TYPE = ARRAY BinNumber OF Recipient; OverflowPage: TYPE = RECORD [slots: ARRAY OverflowSlot OF Recipient, link: Overflow]; Overflow: TYPE = POINTER TO OverflowPage; LengthStructure: TYPE = MACHINE DEPENDENT RECORD [SELECT OVERLAID * FROM chars => [left, right: CHARACTER], word => [val: CARDINAL], ENDCASE]; bins: POINTER TO Bins; overflow: Overflow; overflowFF: OverflowSlot; stringSpace: vmD.ComposedMessagePtr _ NIL; longestRecipientSeen: CARDINAL; recipients: CARDINAL; emptyBin: Recipient = [index: LAST[vmD.CharIndex], link: NIL]; InitializeRecipientList: PUBLIC PROCEDURE = -- initializes the storage of recipient names. BEGIN i: BinNumber; p: POINTER; bins _ overflow _ p _ Storage.Pages[1]; FOR i IN BinNumber DO bins[i] _ emptyBin; ENDLOOP; overflowFF _ LAST[BinNumber]+1; overflow.link _ NIL; longestRecipientSeen _ recipients _ 0; stringSpace _ vmD.AllocateComposedMessageObject[]; vmD.InitComposedMessage[stringSpace, NIL]; END; -- of InitializeRecipientList -- FlushRecipientList: PUBLIC PROCEDURE = -- releases the storage for recipient names. BEGIN p: Overflow; UNTIL overflow = NIL DO p _ overflow.link; Storage.FreePages[overflow]; overflow _ p; ENDLOOP; vmD.FreeVirtualMessageObject[stringSpace]; END; -- of FlushRecipientList -- EnumerateRecipientList: PUBLIC PROCEDURE [space: CARDINAL, proc: PROCEDURE[s: STRING] RETURNS[BOOLEAN]] RETURNS [outcome: BOOLEAN] = -- runs through the recipient list, calling 'proc' with each one BEGIN s: STRING; i: BinNumber; j: CARDINAL; index: vmD.CharIndex; recipient: RecipientHandle; outcome _ FALSE; IF recipients ~= 0 THEN BEGIN s _ Storage.String[longestRecipientSeen+ space]; FOR i IN BinNumber DO recipient _ @bins[i]; IF recipient^ ~= emptyBin THEN DO s.length _ GetStringLength[index _ recipient.index]; index _ index + 2; FOR j IN [0 .. s.length) DO s[j] _ vmD.GetMessageChar[stringSpace, index+j]; ENDLOOP; IF (outcome _ proc[s ! UNWIND => Storage.FreeString[s]]) THEN GO TO Done; IF (recipient _ recipient.link) = NIL THEN EXIT; ENDLOOP; REPEAT Done => NULL; ENDLOOP; Storage.FreeString[s]; END; END; -- of EnumerateRecipientList -- InsertRecipientInList: PUBLIC PROCEDURE [s: STRING] = -- inserts 's' in the list of recipients, checking first to ensure it is not already present. BEGIN recipient: RecipientHandle; insertionPoint: vmD.CharIndex; i: CARDINAL; LowerCase: PROCEDURE[ch: CHARACTER] RETURNS [CHARACTER] = INLINE BEGIN caseBit: WORD = 40B; RETURN[Inline.BITOR[ch, caseBit]] END; -- of LowerCase -- Hash: PROCEDURE RETURNS [bin: BinNumber] = BEGIN HashStructure: TYPE = MACHINE DEPENDENT RECORD[ SELECT OVERLAID * FROM chars => [length: LengthStructure, s0, s1: CHARACTER], words => [w1, w2: WORD], ENDCASE]; h: HashStructure; h _ SELECT s.length FROM 0 => [chars[length: [word[val: 0]], s0: 0C, s1: 0C]], 1 => [chars[length: [word[val: 1]], s0: LowerCase[s[0]], s1: 0C]], ENDCASE => [chars[length: [word[val: s.length]], s0: LowerCase[s[0]], s1: LowerCase[s[1]]]]; RETURN[Inline.BITXOR[h.w1, h.w2] MOD maxBins] END; -- of Hash -- EquivalentRecipient: PROCEDURE[index: vmD.CharIndex] RETURNS [BOOLEAN] = BEGIN i: Byte; IF GetStringLength[index] ~= s.length THEN RETURN[FALSE]; index _ index + 2; -- skip over length field FOR i IN [0 .. s.length) DO IF LowerCase[vmD.GetMessageChar[stringSpace, index + i]] ~= LowerCase[s[i]] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] END; -- of EquivalentRecipient -- recipient _ @bins[Hash[]]; IF recipient^ ~= emptyBin THEN -- bin non-empty BEGIN DO IF EquivalentRecipient[recipient.index] THEN RETURN; -- s duplicates existing entry IF recipient.link = NIL THEN EXIT ELSE recipient _ recipient.link; ENDLOOP; recipient.link _ @overflow.slots[overflowFF]; IF overflowFF = LAST[OverflowSlot] THEN BEGIN p: POINTER; newOverflow: Overflow; newOverflow _ p _ Storage.Pages[1]; newOverflow.link _ overflow; overflow _ newOverflow; overflowFF _ FIRST[OverflowSlot]; END ELSE overflowFF _ overflowFF+1; recipient _ recipient.link; END; BEGIN OPEN vmD; length: LengthStructure = [word[val: s.length]]; insertionPoint _ GetMessageSize[stringSpace]; StartMessageInsertion[stringSpace, insertionPoint]; InsertMessageChar[stringSpace, length.left]; InsertMessageChar[stringSpace, length.right]; FOR i IN [0 .. s.length) DO InsertMessageChar[stringSpace, s[i]]; ENDLOOP; StopMessageInsertion[stringSpace]; END; recipient^ _ [index: insertionPoint, link: NIL]; longestRecipientSeen _ MAX [longestRecipientSeen, s.length]; recipients _ recipients + 1; END; -- of InsertRecipientInList -- GetRecipients: PUBLIC PROCEDURE RETURNS [CARDINAL] = {RETURN[recipients]}; GetStringLength: PROCEDURE [index: vmD.CharIndex] RETURNS [CARDINAL] = -- extracts the string length for the recipient beginning at 'index'. BEGIN length: LengthStructure; length.left _ vmD.GetMessageChar[stringSpace, index]; length.right _ vmD.GetMessageChar[stringSpace, index + 1]; RETURN[length.val] END; -- of GetStringLength -- END. -- of RecipientList --z20461d3008(529)\f1