<> <> <> <> <<>> DIRECTORY Atom, RefTab, RuntimeError, Xl, XlDispatch, XlExtensions, XlPrivateTypes; XlExtensionsImpl: CEDAR MONITOR LOCKS c USING c: Connection IMPORTS Atom, RefTab, Xl, XlDispatch EXPORTS Xl, XlExtensions SHARES XlPrivateTypes = BEGIN OPEN Xl, XlExtensions; <>ConnectionPrivate: PUBLIC TYPE = XlPrivateTypes.ConnectionPrivateImplRec; extensionClassTable: RefTab.Ref ¬ RefTab.Create[]; ProcessExtensionEvent: PUBLIC PROC [xEvent: REF Xl.EventRep.extension] RETURNS [BOOL] = { dispatch: BYTE ~ xEvent.originalCodeByte MOD 128; IF dispatch>=XlExtensions.firstExtension THEN { cp: REF XlPrivateTypes.ConnectionPrivateImplRec ~ xEvent.connection.cPriv; ext: Extension ~ cp.extensions[dispatch]; IF ext#NIL THEN { cont: XlExtensions.ExtensionContinue; xEvent.extension ¬ ext.class.key; cont ¬ ext.class.processEvents[ext, xEvent]; SELECT cont FROM dispatch => {XlDispatch.FindAndDispatch[xEvent]; RETURN [FALSE]}; noop => RETURN [FALSE]; reuse => RETURN [TRUE]; ENDCASE; }; }; RETURN [TRUE]; }; DefineExtensionClass: PUBLIC PROC [key: ATOM, processEvents: ProcessExtensionEventProc, majorEventsCnt: NAT] = { s: REF ExtensionClass ¬ NEW[ExtensionClass ¬ [key: key, processEvents: processEvents, majorEventsCnt: majorEventsCnt]]; [] ¬ RefTab.Store[extensionClassTable, key, s]; }; StartExtension: PUBLIC PROC [c: Connection, key: ATOM] RETURNS [e: Extension ¬ NIL] = { Protected: PROC [c: Connection, key: ATOM] RETURNS [Extension] = { ex: Extension; class: REF ExtensionClass; qer: QueryExtensionRec; cp: REF XlPrivateTypes.ConnectionPrivateImplRec ~ c.cPriv; WITH RefTab.Fetch[cp.extensionTab, key].val SELECT FROM ex: Extension => RETURN [ex]; x: ATOM => RETURN [NIL]; ENDCASE => {}; WITH RefTab.Fetch[extensionClassTable, key].val SELECT FROM x: REF ExtensionClass => class ¬ x; ENDCASE => RETURN [NIL]; qer ¬ Xl.QueryExtension[c, Atom.GetPName[key] ! Xl.XError, UNCAUGHT => {qer.presentOnServer ¬ FALSE; CONTINUE} ]; IF ~qer.presentOnServer THEN { [] ¬ RefTab.Store[cp.extensionTab, key, $no]; RETURN [NIL]; }; ex ¬ NEW[ExtensionRec ¬ [majorOpcode: qer.majorOpcode, firstEvent: qer.firstEvent, firstError: qer.firstError, class: class]]; FOR i: NAT IN [0..class.majorEventsCnt) DO cp.extensions[ex.firstEvent+i] ¬ ex; ENDLOOP; [] ¬ RefTab.Store[cp.extensionTab, key, ex]; RETURN [ex]; }; DefineExtensionTab: ENTRY PROC [c: Connection, cp: REF XlPrivateTypes.ConnectionPrivateImplRec] = { IF cp.extensionTab=NIL THEN cp.extensionTab ¬ RefTab.Create[]; }; cp: REF XlPrivateTypes.ConnectionPrivateImplRec ~ c.cPriv; IF cp.extensionTab=NIL THEN DefineExtensionTab[c, cp]; WITH RefTab.Fetch[cp.extensionTab, key].val SELECT FROM ex: Extension => RETURN [ex]; x: ATOM => RETURN [NIL]; ENDCASE => {}; EnterExtensionLock[c]; e ¬ Protected[c, key ! UNCAUGHT => CONTINUE]; LeaveExtensionLock[c]; }; extensionLock: REF ~ NEW[INT]; checkAgain: CONDITION; EnterExtensionLock: ENTRY PROC [c: Connection] = { cp: REF XlPrivateTypes.ConnectionPrivateImplRec ~ c.cPriv; WHILE cp.extensionLock DO WAIT checkAgain ENDLOOP; cp.extensionLock ¬ TRUE; }; LeaveExtensionLock: ENTRY PROC [c: Connection] = { cp: REF XlPrivateTypes.ConnectionPrivateImplRec ~ c.cPriv; cp.extensionLock ¬ FALSE; BROADCAST checkAgain }; END.