<> <> <> DIRECTORY CHNameP2V0 USING [Name], IO USING [STREAM], NSString USING [AppendString, CopyString, EquivalentStrings, FreeString, LogicalLength, MakeString, nullString, ScanForCharacter, String, StringFromMesaString], NSExec, NSTTY USING [PutLine, SetPagination], Process USING [Detach], Rope USING [FromRefText, ROPE], TTY USING [Handle, NewLine, PutCR, PutLine, PutString, UserAbort], TTYExtras USING [], XFormat USING [Handle], XNS USING [Address, unknownAddress], XNSAuth USING [Identity]; NSExecImpl: CEDAR MONITOR IMPORTS NSExec, NSString, NSTTY, Rope, TTY, TTYExtras EXPORTS NSExec = BEGIN OPEN CHName: CHNameP2V0; <<>> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- >> ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- >> Handle: PUBLIC TYPE = RECORD [session: CARDINAL]; Client: TYPE = REF ClientData; ClientData: TYPE = RECORD [ name: NSString.String _ NSString.nullString, -- generic name of this client command: NSExec.Command, -- the "primary" command registered to identify the client in the NSExec and executed by the user to switch to the client's context. acronym: NSString.String _ NSString.nullString, id: NSExec.ClientID, procs: NSExec.ClientProcs, initialized: BOOLEAN _ FALSE, next: Client _ NIL]; -- pointer to next node in list ExecData: TYPE = REF RECORD [data: SEQUENCE length: CARDINAL OF ExecObject]; ExecObject: TYPE = RECORD [ tty: TTY.Handle, output: XFormat.Handle, currentClient: Client _ NIL, okForAsyncMessage: BOOLEAN _ FALSE, -- between commands qTop: CARDINAL _ 0, -- index of first free queue slot in asyncQ asyncQList: AsyncQList, hostName: NSString.String _ NSString.nullString, -- of connected m/c user: SELECT loggedOnStatus: * FROM loggedOn => [ userName: CHName.Name _ [NIL, NIL, NIL], userIdentity: XNSAuth.Identity _ NIL, <> userAServerSA, userEnabled: BOOLEAN _ FALSE], notLoggedOn => NULL, ENDCASE _ notLoggedOn[]]; AsyncQList: TYPE = RECORD[q: QArray]; QArray: TYPE = ARRAY [0..qSize) OF QEntry; QEntry: TYPE = RECORD [time: CARD _ 0, message: NSString.String _ NIL]; qSize: CARDINAL = 3; ActiveServices: TYPE = REF ActiveStatus; ActiveStatus: TYPE = RECORD [name: NSString.String, next: ActiveServices]; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- >> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- >> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> localExec: PUBLIC READONLY Handle; -- handle for the local TTY totalClients: CARDINAL _ 0; firstClient: PUBLIC Client _ NIL; execData: ExecData _ NIL; serverName: CHName.Name _ [NIL, NIL, NIL]; serverDesc: NSString.String _ NSString.nullString; serverIdentity: XNSAuth.Identity; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- >> Error: PUBLIC ERROR [type: NSExec.Errortype] = CODE; NotFound: ERROR = CODE; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> AssignClientID: PUBLIC ENTRY PROCEDURE RETURNS [NSExec.ClientID] = { ENABLE UNWIND => NULL; RETURN[[totalClients _ totalClients + 1]]}; CreateClient: PUBLIC ENTRY PROCEDURE [id: NSExec.ClientID, command: NSExec.Command, procs: NSExec.ClientProcs, acronym: NSString.String] = BEGIN ENABLE UNWIND => NULL; IF NOT ValidID[id] THEN RETURN WITH ERROR NSExec.Error[invalidID]; IF command.name.length = 0 OR acronym.length = 0 THEN RETURN WITH ERROR NSExec.Error[invalidString]; BEGIN clientName: NSString.String _ NSString.CopyString[command.name]; firstClient _ NEW[ClientData _ [name: clientName, command: [clientName, command.proc, command.activityCheck, command.helpProc], acronym: NSString.CopyString[acronym], id: id, procs: procs, next: firstClient]]; END; END; -- CreateClient DestroyClient: PUBLIC ENTRY PROCEDURE [id: NSExec.ClientID] = BEGIN ENABLE UNWIND => NULL; client, predecessor: Client; [client, predecessor] _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]]; <> IF predecessor = NIL THEN firstClient _ client.next ELSE predecessor.next _ client.next; END; -- DestroyClient EnumerateClients: PUBLIC PROCEDURE [enumProc: NSExec.EnumerateClientProc] = BEGIN continue: BOOLEAN _ TRUE; FOR client: Client _ firstClient, client.next UNTIL client = NIL OR NOT continue DO IF ~client.initialized THEN LOOP; continue _ enumProc[client.id, client.command, Rope.FromRefText[client.acronym], client.procs] ENDLOOP; END; -- EnumerateClients ClientState: PUBLIC PROCEDURE [id: NSExec.ClientID] RETURNS [activated, initialized: BOOLEAN] = BEGIN client: Client _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]].client; activated _ Activated[client.name]; initialized _ client.initialized; END; -- ClientState AddClientCommands: PUBLIC PROCEDURE [id: NSExec.ClientID, commands: NSExec.Commands] = BEGIN ENABLE UNWIND => NULL; client: Client _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]].client; FOR i: CARDINAL IN [0..commands.length) DO AddCommand[commands[i], client] ENDLOOP END; -- AddClientCommands <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> CreateExec: PUBLIC PROCEDURE [tty: TTY.Handle, host: XNS.Address] = BEGIN ENABLE ABORTED => CONTINUE; <<<< ASSERT: 1) All calls to this proc are for OTHER than the local exec. 2) The server profile has been established. >>>> <> DisplayHerald[tty: tty, displayTime: FALSE]; -- may raise ABORTED ExecProcess[CreateExecInternal[tty, host].exec]; END; -- CreateExec EnumerateExecs: PUBLIC PROCEDURE [enumProc: NSExec.EnumerateExecProc] = {}; <> <> <> < CONTINUE]};>> < CONTINUE]};>> AddExecCommand: PUBLIC PROCEDURE [command: NSExec.Command, unload: PROCEDURE _ NIL] = BEGIN AddCommand[command: command, client: NIL, unload: unload]; END; -- AddExecCommand <> <> GetTTY: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [tty: TTY.Handle] = { RETURN[execData.data[exec.session].tty]}; CheckForAbort: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [abort: BOOLEAN] = {RETURN[TTY.UserAbort[NSExec.GetTTY[exec]]]}; SetContext: PUBLIC PROCEDURE [exec: Handle, id: NSExec.ClientID, context: NSExec.Context, terminationHandler: NSExec.TerminationHandler] = BEGIN <> <> <<>> <> < {noContext _ TRUE; CONTINUE}];>> <> <> <> <> <> <> <> END; -- SetContext GetContext: PUBLIC PROCEDURE [exec: Handle, id: NSExec.ClientID] RETURNS [context: LONG UNSPECIFIED] = BEGIN <> <> <> < IF type = notSet THEN NSExec.Error[noContextSet]];>> <> RETURN[LONG[0]]; END; -- of GetContext DestroyContext: PUBLIC PROCEDURE [exec: Handle, id: NSExec.ClientID] = BEGIN <> < GOTO NoContext];>> < ERROR NSExec.Error[noContextSet];>> END; -- of DestroyContext <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- >> BroadcastAsyncMessage: PUBLIC PROCEDURE [string: NSString.String, id: NSExec.ClientID] = { broadcastMessage: NSExec.EnumerateExecProc = {PutAsyncMessage[exec, string, id]}; NSExec.EnumerateExecs[broadcastMessage]}; -- of BroadcastAsyncMessage PutAsyncMessage: PUBLIC PROCEDURE [exec: NSExec.Handle, string: NSString.String, id: NSExec.ClientID] = BEGIN client: Client _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]].client; msg: NSString.String _ NSString.MakeString[client.acronym.length + 2 + string.length]; tty: TTY.Handle; -- should be initialized within the catch phase for NSSession.Error BEGIN ENABLE --NSSession.Error, --ABORTED => {NSString.FreeString[msg]; CONTINUE}; msg _ NSString.AppendString[msg, client.acronym]; msg _ NSString.AppendString[msg, NSString.StringFromMesaString[": "]]; msg _ NSString.AppendString[msg, string]; IF TTY.NewLine[tty _ NSExec.GetTTY[exec]] OR OkForAsyncMsg[exec] THEN { oldPageLength: CARDINAL _ NSTTY.SetPagination[h: tty, pageLength: 0]; -- eliminates (more) PutMessage[exec, msg]; [] _ NSTTY.SetPagination[h: tty, pageLength: oldPageLength]; NSString.FreeString[msg]} ELSE TRUSTED {Process.Detach[FORK PutAsyncMessageEntry[exec, msg]]}; END; -- ENABLE END; -- PutAsyncMessage PutErrorMessage, PutIndentedMessage: PUBLIC PROCEDURE [exec: NSExec.Handle, string: NSString.String] = BEGIN tty: TTY.Handle _ NSExec.GetTTY[exec]; IF ~TTY.NewLine[tty] THEN TTY.PutCR[tty]; TTY.PutString[tty, " "]; NSTTY.PutLine[tty, string]; END; -- PutErrorMessage, PutIndentedMessage PutMessage: PUBLIC PROCEDURE [exec: NSExec.Handle, string: NSString.String] = BEGIN tty: TTY.Handle _ NSExec.GetTTY[exec]; IF ~TTY.NewLine[tty] THEN TTY.PutCR[tty]; NSTTY.PutLine[tty, string]; END; -- PutMessage OutputHandle: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [output: XFormat.Handle] = {RETURN[(execData[exec.session].output)]}; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <<>> UserName: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [name: CHName.Name _ [NIL, NIL, NIL]] = {RETURN[LoggedOnData[exec].userName]}; UserIdentity: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [identity: XNSAuth.Identity] = {RETURN[LoggedOnData[exec].userIdentity]}; <<>> <> UserState: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [loggedOn, serverSA, enabled: BOOLEAN _ FALSE] = TRUSTED { data: ExecObject = execData[exec.session]; WITH d: data SELECT FROM loggedOn => {loggedOn _ TRUE; serverSA _ d.userAServerSA; enabled _ d.userEnabled}; ENDCASE => NULL; }; UserAServerSA: PUBLIC NSExec.Predicate = {RETURN[UserState[exec].serverSA]}; UserEnabled: PUBLIC NSExec.Predicate = {RETURN[UserState[exec].enabled]}; UserLoggedOn: PUBLIC NSExec.Predicate = {RETURN[UserState[exec].loggedOn]}; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> Genesis: PUBLIC NSExec.Predicate = {RETURN[FALSE]}; GenesisOrEnabledSA: PUBLIC NSExec.Predicate = {RETURN[TRUE]}; GenesisOrSA: PUBLIC NSExec.Predicate = {RETURN[TRUE]}; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> ServerName: PUBLIC PROCEDURE RETURNS [name: CHName.Name] = { RETURN[serverName]}; ServerIdentity: PUBLIC PROCEDURE RETURNS [identity: XNSAuth.Identity] = { RETURN[serverIdentity]}; <<>> <> SystemDirectory: PUBLIC PROCEDURE RETURNS [directory: Rope.ROPE] = { RETURN["///System/"]}; WorkingDirectory: PUBLIC PROCEDURE RETURNS [directory: Rope.ROPE] = { RETURN["///Working/"]}; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> Run: PROCEDURE [name: ROPE, exec: Handle, codeLinks: BOOLEAN _ FALSE] = {}; <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> <> <<-- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -->> Activated: PUBLIC --NSExecInternal-- PROCEDURE [name: NSString.String] RETURNS [BOOLEAN _ FALSE] = BEGIN FOR s: ActiveServices _ activeServices, s.next UNTIL s = NIL DO IF NSString.EquivalentStrings[name, s.name] THEN RETURN[TRUE]; ENDLOOP; END; -- Activated AddCommand: ENTRY PROCEDURE [command: NSExec.Command, client: Client, clientName: BOOLEAN _ FALSE, unload: PROCEDURE _ NIL] = BEGIN ENABLE UNWIND => NULL; length: CARDINAL _ NSString.LogicalLength[command.name]; pos, offset: CARDINAL _ 0; list: Entry _ topEntry; commandWord: NSString.SubStringDescriptor; IF length = 0 THEN ERROR NSExec.Error[invalidString]; DO pos _ NSString.ScanForCharacter[c: [0, LOOPHOLE[Ascii.SP]], s: command.name, start: offset]; SELECT pos FROM offset => {offset _ offset + 1; LOOP}; -- skip spaces LAST[CARDINAL] => { commandWord _ [command.name, offset, length - offset]; list _ InsertWordInList[list, commandWord]; EXIT}; ENDCASE => { commandWord _ [command.name, offset, pos - offset]; list _ InsertWordInList[list, commandWord]; offset _ pos + 1}; ENDLOOP; BEGIN -- begin exits DuplicateCommand IF clientName THEN {IF list.commandProcs # NIL THEN GOTO DuplicateCommand ELSE {list.commandProcs _ NEW[clientName ProcData _ [ execute: command.proc, activityProc: command.activityCheck, helpProc: command.helpProc, commandType: clientName[client]]]}} ELSE BEGIN p: NSExecInternal.Procs; FOR p _ list.commandProcs, p.next UNTIL p = NIL DO WITH commandProc: p SELECT FROM exec, clientName => GOTO DuplicateCommand; client => IF commandProc.client = client THEN GOTO DuplicateCommand; ENDCASE ENDLOOP; IF client = NIL THEN -- exec command p _ NEW[exec ProcData _ [execute: command.proc, activityProc: command.activityCheck, helpProc: command.helpProc, commandType: exec[unload]]] ELSE -- client command p _ NEW[client ProcData _ [next: list.commandProcs, execute: command.proc, activityProc: command.activityCheck, helpProc: command.helpProc, commandType: client[client]]]; list.commandProcs _ p; END; EXITS DuplicateCommand => { s: LONG STRING _ [128]; nss: NSString.String _ NSString.StringFromMesaString[s]; o: XFormat.Object _ XFormat.NSStringObject[@nss]; SCSCommon.FormatExpandedMsg[@o, M[keyDuplicateCommand], command.name]; NSExec.BroadcastAsyncMessage[nss, NSExec.nullClientID]}; END; -- of exits DuplicateCommand END; -- AddCommand CreateExecInternal: PUBLIC PROCEDURE [tty: TTY.Handle, hostName: XNS.Address _ XNS.unknownAddress] RETURNS [exec: Handle, execData: ExecData] = BEGIN nss: NSString.String _ NSString.MakeString[100]; object: XFormat.Handle _ XFormat.NSStringObject[nss]; asyncQ: AsyncQList; XFormat.NetworkAddress[object, hostName, productSoftware]; execData _ NEW[ExecObject _ [tty: tty, asyncQList: asyncQ, output: XFormat.TTYObject[tty], hostName: NSString.CopyString[nss]]]; <> <> END; -- of CreateExecInternal DisplayHerald: PUBLIC -- NSExecInternal -- PROCEDURE [tty: TTY.Handle, displayTime: BOOLEAN _ TRUE] = BEGIN o: XFormat.Handle _ XFormat.TTYObject[tty]; PutHerald: PROCEDURE [s: NSString.String] = {NSTTY.PutString[tty, s]}; PutBcdTime: PROCEDURE = BEGIN XFormat.Date[h: o, time: Loader.BCDBuildTime[DisplayHerald]]; END; -- PutBcdTime <> TTY.PutCR[tty]; NSHerald.GetExecHerald[PutHerald]; NSTTY.PutString[tty, " of "]; PutBcdTime[]; IF displayTime THEN XFormat.Date[o, BasicTime.Now[], dateAndTime]; TTY.PutCR[tty]; NSHerald.GetCopyrightMsg[PutHerald]; END; -- DisplayHerald ExecProcess: PUBLIC PROCEDURE [exec: Handle] = BEGIN ENABLE UNWIND => {}; -- FreeExecData[exec]; [] _ NSTTY.SetPagination[NSExec.GetTTY[exec], 23]; IF NSExec.ServerName[] # NIL AND exec # LOOPHOLE[NSExec.localExec] THEN DisplayServerName[exec]; -- may raise ABORTED ProcessCommands[exec]; <> END; -- ExecProcess FindClient: PUBLIC --NSExecInternal-- PROCEDURE [id: CARDINAL] RETURNS [client, predecessor: Client _ NIL] = BEGIN FOR client _ firstClient, client.next UNTIL client = NIL DO IF client.id = id THEN RETURN; predecessor _ client; ENDLOOP; ERROR NotFound; END; -- FindClient LoggedOnData: PROCEDURE [exec: Handle] RETURNS [REF loggedOn ExecObject] = { data: ExecObject = execData[exec]; WITH d: data SELECT FROM loggedOn => {data: REF loggedOn ExecObject _ d; RETURN[data]}; ENDCASE => NSExec.Error[noUser]}; OkForAsyncMsg: PROC [exec: Handle] RETURNS [okForAsyncMessage: BOOLEAN _ FALSE] = { <> <> }; PutAsyncMessageEntry: ENTRY PROCEDURE [exec: Handle, s: NSString.String] = BEGIN ENABLE UNWIND => NULL; < NULL; NSSession.Error => CONTINUE};>> <> <> <> <= longAsyncDelayInMilliSec -- queue is old>> <> <> <> <> <> <> <> <> <> <> <> < CONTINUE; -- can be raised by ANY call to TTY>> <> <> <> <> END; -- PutAsyncMessageEntry ValidID: PUBLIC --NSExecInternal-- PROCEDURE [id: NSExec.ClientID] RETURNS [BOOLEAN] = {RETURN[id IN [1..totalClients]]}; END. LOG [Time - Person - Action] 14-Nov-83 8:54:49 - McManis - Created file. 3-Jan-84 15:16:44 - McManis - Added nullHandle, nullClientID, Context and TerminationHandler. Changed SetContext and GetContext to use Context and TerminationHandler. Renamed OutputObject to OutputHandle and changed it to return XFormat.Handle. Changed CreateExec to take "host: System.NetworkAddress" rather than credentials. 29-Apr-85 15:52:51 - McManis - Added cannotExpunge and cannotInitialize to ErrorType. Removed notInitialized from ClientStatus. Added predicates for Genesis.