-- File [Ivy]<Nelson>Lupine>LupineUserInterfaceImpl.mesa. -- Last edited by BZM on 2-May-82 23:18:33. -- This interface uses a standard command interpreter called the Commander, -- which is also used by the Lister. While its teletype style of interaction -- is poor compared to the tools paradigm, it has the great advantage of -- being called from the command line, therefore making Lupine easily -- useable from command files. Keep this in mind before discarding the -- Commander for something else. All anticipated clients intend to use -- Lupine via command files. DIRECTORY CWF USING [SetWriteProcedure, SWF1, WF0, WF1, WF2, WFCR], CommanderDefs USING [ AddCommand, CommandBlockHandle, InitCommander, WaitCommands], Exec USING [AddCommand, w], LongString USING [EquivalentStrings], LupineManager USING [ ErrorHandlerProc, Language, ParamPassingMethod, String, TranslateRemoteInterface], Runtime USING [CallDebugger, GetBcdTime], System USING [GreenwichMeanTime], TTY USING [PutChar, ResetUserAbort, UserAbort]; LupineUserInterfaceImpl: PROGRAM IMPORTS CommanderDefs, CWF, Exec, LongString, LupineManager, Runtime, TTY = BEGIN -- Initialization and command procedures. herald: STRING = [100]; PutLogChar: PROC [char: CHARACTER] = {TTY.PutChar[Exec.w, char]}; StartLupine: PROCEDURE = BEGIN buildTime: System.GreenwichMeanTime ← Runtime.GetBcdTime[]; CWF.SWF1[herald, "*NLupine 1 of %LT: Cedar's RPC Stub Translator."L, @buildTime ]; CommanderDefs.InitCommander[herald]; AddLupineCommands; [] ← CWF.SetWriteProcedure[PutLogChar]; Exec.AddCommand["Lupine.~"L, RunLupine]; END; RunLupine: PROCEDURE = {SetCommandDefaults; CommanderDefs.WaitCommands[]}; CheckAbort: PROCEDURE = -- IF ControlDEL then cause process ABORT thru Commander to Executive. -- The Exec will catch it and UNWIND us, and then the Commander too. BEGIN IF TTY.UserAbort[] THEN {TTY.ResetUserAbort; ERROR ABORTED}; END; -- Command definitions for the Commander. AddLupineCommands: PROCEDURE = -- The Commander does not make copies of these strings and -- expects them to last forever (e.g., live in a global frame). BEGIN OPEN CommanderDefs; cmd: CommandBlockHandle; cmd ← AddCommand["TranslateInterface", LOOPHOLE[TranslateInterface], 1]; cmd.params[0] ← [type: string, prompt: "Filename of compiled remote interface"]; cmd ← AddCommand[ "TargetLanguage", LOOPHOLE[SetTargetLanguage], 1]; cmd.params[0] ← [type: string, prompt: "Target language for RPC modules (Cedar, Mesa) [Cedar]"]; cmd ← AddCommand[ "DefaultParameterPassing", LOOPHOLE[SetParameterPassing], 1]; cmd.params[0] ← [type: string, prompt: "Default passing method (VAR, VALUE, RESULT, HANDLE) [VALUE]"]; cmd ← AddCommand["InterMdsCalls", LOOPHOLE[SetInterMdsCalls], 1]; cmd.params[0] ← [type: boolean, prompt: "Translate interfaces to handle interMDS calls only [FALSE]"]; cmd←AddCommand["FreeServerArguments", LOOPHOLE[SetFreeServerArgs], 1]; cmd.params[0] ← [type: boolean, prompt: "Automatically deallocate all server heap arguments [TRUE]"]; cmd ← AddCommand["InlineDispatcherStubs", LOOPHOLE[SetInlineStubs], 1]; cmd.params[0] ← [type: boolean, prompt: "Use INLINE stubs in the RpcServerImpl's dispatcher [TRUE]"]; cmd←AddCommand["DynamicHeapNEWs", LOOPHOLE[SetDynamicHeapNEWs], 2]; cmd.params[0] ← [type: numeric, prompt: "Maximum number of dynamic heap NEWs per call [50]"]; cmd.params[1] ← [type: numeric, prompt: "Maximum number of dynamic MDS NEWs per call [50]"]; cmd ← AddCommand["LineLength", LOOPHOLE[SetLineLength], 1]; cmd.params[0] ← [type: numeric, prompt: "Desired line length of output files [82]"]; cmd ← AddCommand["Spy", LOOPHOLE[CallSpy], 0]; cmd ← AddCommand["CallDebugger", LOOPHOLE[SetCallDebugger], 1]; cmd.params[0] ← [type: boolean, prompt: "For wizards only: Call debugger on user errors [FALSE]"]; END; -- AddLupineCommands. -- Individual command processors. targetLanguage: LupineManager.Language; defaultParamPassing: LupineManager.ParamPassingMethod; interMdsCalls: BOOLEAN; freeServerArgs: BOOLEAN; inlineDispatcherStubs: BOOLEAN; maxHeapAllocs, maxMdsAllocs: LONG INTEGER; lineLength: LONG INTEGER; callDebugger: BOOLEAN; SetCommandDefaults: PROCEDURE = INLINE BEGIN targetLanguage ← Cedar; defaultParamPassing ← Value; interMdsCalls ← FALSE; freeServerArgs ← TRUE; inlineDispatcherStubs ← TRUE; maxHeapAllocs ← maxMdsAllocs ← 50; lineLength ← 82; callDebugger ← FALSE; END; TranslateInterface: PROCEDURE [interfaceFile: STRING] = BEGIN OPEN CWF; aborted, errors, warnings: BOOLEAN ← FALSE; HandleError: LupineManager.ErrorHandlerProc = -- PROCEDURE [type: ErrorType, code: ErrorCode, -- codeExplanation: String, -- outputFileName: String←StringNIL, -- outputFileCharPosition: LONG INTEGER, -- problemCausingText: String←NIL ] -- RETURNS [abortTranslation: BOOLEAN←FALSE]; BEGIN CheckAbort; SELECT type FROM abort => { aborted ← TRUE; WF0["*NFatal error"L] }; error => { errors ← TRUE; WF0["*NError"L] }; warning => { warnings ← TRUE; WF0["*NWarning"L] }; ENDCASE => NULL; IF outputFileName # NIL THEN WF2[" at %S[%LD]"L, outputFileName, @outputFileCharPosition]; WF1[":*N %S*N"L, codeExplanation]; IF problemCausingText # NIL THEN WF1[ " Problem-causing file, module, identifier, or type: %S*N"L, problemCausingText ]; IF callDebugger THEN Runtime.CallDebugger["Tracking a Lupine problem..."L]; RETURN [abortTranslation: FALSE]; END; -- HandleError. CheckAbort; LupineManager.TranslateRemoteInterface [ interfaceBcdFilename: interfaceFile, errorHandler: HandleError, options: [ targetLanguage: targetLanguage, defaultParamPassing: (IF interMdsCalls THEN InterMds ELSE defaultParamPassing), freeServerArguments: freeServerArgs, inlineServerDispatcherStubs: inlineDispatcherStubs, maxHeapAllocations: maxHeapAllocs, maxMdsAllocations: maxMdsAllocs ], desiredLineLength: lineLength ]; IF aborted OR errors OR warnings THEN WFCR; WF2["Translation of %S %S.*N*N"L, interfaceFile, (SELECT TRUE FROM aborted => "aborted"L, errors => "finished with errors"L, warnings => "finished with warnings"L, ENDCASE => "complete"L) ]; END; -- TranslateInterface. SetTargetLanguage: PROCEDURE [language: STRING] = BEGIN OPEN LongString; SELECT TRUE FROM EquivalentStrings[language, "Cedar"L] => targetLanguage ← Cedar; EquivalentStrings[language, "Mesa"L] => targetLanguage ← Mesa; ENDCASE => CWF.WF0[" Invalid language--no change made!*N"L]; END; SetParameterPassing: PROCEDURE [kind: STRING] = BEGIN OPEN LongString; SELECT TRUE FROM EquivalentStrings[kind, "VAR"L] => defaultParamPassing ← Var; EquivalentStrings[kind, "VALUE"L] => defaultParamPassing ← Value; EquivalentStrings[kind, "RESULT"L] => defaultParamPassing ← Result; EquivalentStrings[kind, "HANDLE"L] => defaultParamPassing ← Handle; ENDCASE => CWF.WF0[" Invalid passing method--no change made!*N"L]; END; SetInterMdsCalls: PROCEDURE [onOff: BOOLEAN] = {interMdsCalls ← onOff}; SetFreeServerArgs: PROCEDURE [onOff: BOOLEAN] = BEGIN freeServerArgs ← onOff END; SetInlineStubs: PROCEDURE [onOff: BOOLEAN] = BEGIN inlineDispatcherStubs ← onOff END; SetDynamicHeapNEWs: PROCEDURE [heap, mds: CARDINAL] = BEGIN maxHeapAllocs ← heap; maxMdsAllocs ← mds END; SetLineLength: PROCEDURE [length: CARDINAL] = {lineLength ← length}; SetCallDebugger: PROCEDURE [onOff: BOOLEAN] = {callDebugger ← onOff}; CallSpy: PROCEDURE = {Runtime.CallDebugger["Do some spying..."L]}; -- Module Initialization. StartLupine; END.