<> <> <> DIRECTORY Convert USING [CardFromRope, Error], CountedVM USING [SimpleAllocate, Free, Handle], FS USING [Open, OpenFile, Close, Error, Read], IO, MessageFileFormat USING [Domain, FileHeader, Segment, TextEntry], NSString USING [nullString, String], PrincOps USING [wordsPerPage], PrincOpsUtils USING [LongCopy], Rope USING [FromRefText, Length, ROPE, ToRefText], VM USING [PageCount, WordsForPages], XMessage USING [ClientData, DestroyMsgsProc, ErrorType, Messages, MsgDomains, MsgKey, MsgKeyList, StringArray], XMessagePrivate USING [FileInfo, FileInfoObject, Object]; XMessageImpl: PROGRAM IMPORTS Convert, CountedVM, FS, IO, PrincOpsUtils, Rope, VM EXPORTS XMessage = BEGIN OPEN XMessage, MFF: MessageFileFormat; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; initialHeapPages: CARDINAL = 4; heapIncrement: CARDINAL = 4; swapUnitSize: CARDINAL = 4; <> <> leftAngleChar: REF TEXT = "<"; rightAngleChar: REF TEXT = ">"; Handle: TYPE = REF Object; Object: PUBLIC TYPE = XMessagePrivate.Object; Error: PUBLIC ERROR [type: ErrorType] = CODE; AllocateMessages: PUBLIC SAFE PROCEDURE [applicationName: NSString.String, maxMessages: CARDINAL, clientData: ClientData, proc: DestroyMsgsProc] RETURNS [Handle] = TRUSTED BEGIN h: REF rawData Object; h _ NEW[Object.rawData[maxMessages]]; h.proc _ proc; h.clientData _ clientData; FOR i: CARDINAL IN [0..maxMessages) DO h.array[i] _ NSString.nullString; ENDLOOP; RETURN[h]; END; DestroyMessages: PUBLIC SAFE PROCEDURE [h: Handle] = TRUSTED {IF h.proc # NIL THEN h.proc[h.clientData]; WITH hh: h SELECT FROM rawData => {FOR i: CARDINAL IN [0..hh.maxMsgIndex) DO hh.array[i] _ NIL ENDLOOP}; file => {}; ENDCASE; }; Decompose: PUBLIC SAFE PROCEDURE [source: NSString.String] RETURNS [args: REF StringArray] = TRUSTED {RETURN[NIL]}; -- of Decompose Compose: PUBLIC SAFE PROCEDURE [source: NSString.String, args: REF StringArray] RETURNS [destination: NSString.String] = TRUSTED { destination _ ComposeToFormatHandle[source, args]}; ComposeOne: PROCEDURE [source: NSString.String, arg: NSString.String] RETURNS [destination: NSString.String] = TRUSTED { args: REF StringArray _ NEW[StringArray[1]]; args.data[0] _ arg; destination _ ComposeToFormatHandle[source, args]}; ComposeToFormatHandle: PROCEDURE [source: NSString.String, args: REF StringArray] RETURNS [destination: NSString.String] = { TokenProc: IO.BreakProc = TRUSTED BEGIN <> IF char = tokenChar THEN RETURN [sepr] ELSE RETURN [other]; END; tokenChar, c: CHAR; front: ROPE; argIndex, index, length: CARDINAL _ 0; sourceRope: ROPE _ Rope.FromRefText[source]; noNumber: BOOLEAN; inS: STREAM _ IO.RIS[sourceRope]; outS: STREAM _ IO.ROS[]; IF Rope.Length[sourceRope] = 0 THEN Error[invalidString]; IF args = NIL THEN Error[notEnoughArguments]; UNTIL IO.EndOf[inS] DO tokenChar _ '<; front _ IO.GetTokenRope[inS, TokenProc].token; [] _ IO.GetChar[inS]; -- Get rid of the < IO.PutRope[outS, front]; IF ~IO.EndOf[inS] THEN { tokenChar _ '>; front _ IO.GetTokenRope[inS, TokenProc].token; c _ IO.GetChar[inS]; IF c = '> THEN { noNumber _ FALSE; argIndex _ Convert.CardFromRope[front ! Convert.Error => {noNumber _ TRUE; CONTINUE}]; IF noNumber THEN {IO.PutChar[outS, '<]; IO.PutRope[outS, front]; IO.PutChar[outS, '>]} ELSE IO.PutText[outS, args.data[argIndex - 1]]; } ELSE IO.PutRope[outS, front]; }; ENDLOOP; RETURN[Rope.ToRefText[IO.RopeFromROS[outS]]]; }; Get: PUBLIC SAFE PROCEDURE [h: Handle, msgKey: MsgKey] RETURNS [msg: NSString.String] = TRUSTED {RETURN GetInternal[h, msgKey]}; GetList: PUBLIC SAFE PROCEDURE [h: Handle, msgKeys: REF MsgKeyList, msgs: REF StringArray] = TRUSTED BEGIN IF msgKeys = NIL THEN Error[invalidMsgKeyList]; IF msgs = NIL THEN Error[invalidStringArray]; IF msgKeys.length # msgs.length THEN Error[arrayMismatch]; FOR i: CARDINAL IN [0..msgKeys.length) DO msgs[i] _ GetInternal[h, msgKeys[i]] ENDLOOP END; -- of GetList RegisterMessages: PUBLIC SAFE PROCEDURE [h: Handle, messages: REF Messages, stringBodiesAreReal: BOOLEAN] = TRUSTED BEGIN IF messages = NIL THEN Error[notEnoughArguments]; WITH hh: h SELECT FROM rawData => { FOR i: CARDINAL IN [0..messages.length) DO hh.array[messages[i].msgKey] _ messages[i].msg; ENDLOOP}; ENDCASE => ERROR Error[invalidMsgKeyList]; END; -- of RegisterMessages <<<< This proc is commented out because it depends on the BWS file structure which is not available in services.>> <<>> <> <> <> <> <> <>>> MessagesFromReference: PUBLIC SAFE PROCEDURE [file: ROPE, clientData: ClientData, proc: DestroyMsgsProc] RETURNS [msgDomains: REF MsgDomains] = TRUSTED { fileHandle: FS.OpenFile = FS.Open[file ! FS.Error => GOTO Out]; RETURN [MessagesFromFileHandle[fileHandle, clientData, proc]]; EXITS Out => RETURN[NIL]}; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---->> GetInternal: PROCEDURE [h: Handle, msgKey: MsgKey] RETURNS [NSString.String] = BEGIN WITH hh: h SELECT FROM rawData => RETURN[hh.array[msgKey]]; file => { text: LONG POINTER TO MessageFileFormat.TextEntry = @hh.textBase[ hh.domain[hh.messageTable][msgKey]]; rt: REF TEXT _ NEW[TEXT[text.maxLength]]; PrincOpsUtils.LongCopy[ from: LOOPHOLE[LOOPHOLE[text, LONG POINTER] + SIZE[MessageFileFormat.TextEntry]], nwords: text.length/2, to: LOOPHOLE[LOOPHOLE[rt, LONG POINTER] + SIZE[TEXT[0]]]]; RETURN[rt]}; pilotFile => { text: LONG POINTER TO MessageFileFormat.TextEntry = @hh.textBase[ hh.domain[hh.messageTable][msgKey]]; rt: REF TEXT _ NEW[TEXT[text.maxLength]]; PrincOpsUtils.LongCopy[ from: LOOPHOLE[LOOPHOLE[text, LONG POINTER] + SIZE[MessageFileFormat.TextEntry]], nwords: text.length/2, to: LOOPHOLE[LOOPHOLE[rt, LONG POINTER] + SIZE[TEXT[0]]]]; RETURN[rt]}; ENDCASE => ERROR Error[invalidMsgKeyList]; END; <> <> <> FreeMsgDomainsStorage: PUBLIC SAFE PROCEDURE [msgDomains: REF XMessage.MsgDomains] = TRUSTED {}; MessagesFromFileHandle: PROCEDURE [file: FS.OpenFile, clientData: ClientData, proc: DestroyMsgsProc] RETURNS [msgDomains: REF MsgDomains] = TRUSTED { header: MFF.FileHeader; cvmH: CountedVM.Handle _ CountedVM.SimpleAllocate[VM.WordsForPages[1]]; nSegments, nPages: CARDINAL; fileInfo: XMessagePrivate.FileInfo; domainSeq: REF MsgDomains; <> header _ LOOPHOLE[cvmH.pointer]; FS.Read[file: file, from: 0, nPages: 1, to: header]; <
> <> nSegments _ header.nSegments; nPages _ PagesForHeader[nSegments]; IF nPages # 1 THEN { CountedVM.Free[cvmH]; cvmH _ CountedVM.SimpleAllocate[VM.WordsForPages[nPages]]; <<[] _ Space.Unmap[header];>> header _ LOOPHOLE[cvmH.pointer]; FS.Read[file: file, from: 0, nPages: nPages, to: header]; <
> <> <> }; fileInfo _ NEW[XMessagePrivate.FileInfoObject _ [stuff: cvmH, nDomains: nSegments]]; domainSeq _ NEW[MsgDomains[nSegments]]; FOR i: CARDINAL IN [0..nSegments) DO pageCnt: VM.PageCount _ header.segments[i].count; cvmHandel: CountedVM.Handle _ CountedVM.SimpleAllocate[VM.WordsForPages[pageCnt]]; domain: MessageFileFormat.Domain _ -- LONG BASE POINTER TO DomainHeader -- LOOPHOLE[cvmHandel.pointer]; <> <> <> h: REF Object.file _ NEW[Object.file _ [ proc: proc, clientData: clientData, body: file[fileInfo: fileInfo, cvmH: cvmHandel, domain: domain, textBase: @domain[domain.textTable], messageTable: domain.messageTable]]]; text: LONG POINTER TO MessageFileFormat.TextEntry = @h.textBase[domain.domainName]; nsString: REF TEXT _ NEW[TEXT[text.length]]; FS.Read[file: file, from: header.segments[i].base, nPages: header.segments[i].count, to: domain]; FOR j: CARDINAL IN [0 .. text.length) DO nsString[i] _ LOOPHOLE[text.bytes[i]]; ENDLOOP; nsString.length _ text.length; domainSeq.data[i] _ [handle: h, applicationName: nsString]; ENDLOOP; <
> FS.Close[file]; <> RETURN[domainSeq]}; PagesForHeader: PROCEDURE [nSegments: CARDINAL] RETURNS [CARDINAL] = INLINE { wpp: CARDINAL = PrincOps.wordsPerPage; RETURN[(MFF.FileHeader.SIZE + nSegments * MFF.Segment.SIZE + wpp - 1) / wpp]}; END. -- of MessageImpl 30-May-84 16:24:48 - Saund - Reduced initial Heap size from 64 to 4 pages. 7-Jun-84 15:15:52 - Sandman - Remove unused stuff. 23-Jul-84 11:42:42 - Sandman - Make Compose not alter source arg and use 1 relative indexing on args. 25-Jan-85 15:04:08 - Sandman - Implement message file stuff. 30-May-85 16:23:01 - McManis - Comment out MessageFromFile because services cannot use it and there is a conflict of Catalog with NSFile. 12-Sep-85 14:46:09 - McManis - Added check for NIL proc in DestroyMessages. 14-Oct-85 15:30:41 - McManis - Added pilotFile to SELECT in Get to allow messages to be retrieved from pilotFiles.