// IfsTelnet.bcpl -- top level command interpreter and useful subroutines
// Copyright Xerox Corporation 1979, 1980, 1982
// Last modified April 9, 1982 5:14 PM by Taft
get "IfsRs.decl"
get "IfsTelnet.decl"
get "CmdScan.decl"
get "IfsFiles.decl"
external
[
// outgoing procedures
TelnetTopLevel
GetKeywordOrCR; Plural; TelnetAborting; TelnetCommandLoop; TelnetCommandQuit
TelnetSubcommandPrompt; SelectKeyword; CreateKeywordIntegerMap; TelnetConfirm
// incoming procedures
InitTelnetJob; CleanupTelnetJob
InitCmd; GetKeyword; GetPhrase; TerminatingChar; Confirm
CreateKeywordTable; DestroyKeywordTable; InsertKeyword
EnableCatch; DisableCatch; EndCatch
DefaultArgs; ReturnFrom; IFSError; CallWithArgVec
Puts; Endofs; Closes; Resets; Errors; Wss; Ws
// incoming statics
CtxRunning; keys; dsp
atSubPrompt; bangSubPrompt; pluralString; singularString
]
manifest ecReturnFromReturned = 103
//---------------------------------------------------------------------------
let TelnetTopLevel(ctx) be
//---------------------------------------------------------------------------
// Top-level procedure for telnet server context.
[
InitTelnetJob(ctx)
[ //repeat
TelnetCommandLoop(ctx>>TCtx.topKT,
(ctx>>TCtx.userInfo>>UserInfo.capabilities ne 0? "*n!", "*n@"))
if ctx>>TCtx.kill break
if ctx>>TCtx.controlC then
[
Resets(dsp)
Resets(keys)
ctx>>TCtx.controlC = false
Ws("↑C")
]
] repeat
CleanupTelnetJob(ctx)
]
//---------------------------------------------------------------------------
and GetKeywordOrCR(cs, kt) = valof
//---------------------------------------------------------------------------
// Returns pointer to keyword table entry, or zero if just a carriage
// return is typed in.
[
let entry = GetKeyword(cs, kt, true)
if entry eq 0 then
[
Resets(cs)
unless GetPhrase(cs) eq 0 & TerminatingChar(cs) eq $*n do
Errors(cs, ecKeyNotFound)
]
resultis entry
]
//---------------------------------------------------------------------------
and TelnetCommandLoop(kt, prompt, returnOnCR, arg, numChars, numPhrases,
FixedProc; numargs na) be
//---------------------------------------------------------------------------
// Accepts a keyword table kt whose entries are command procedures.
// Repeatedly inputs a command keyword and calls Proc(cs, arg), where
// Proc is the corresponding command procedure. If returnOnCR is true,
// returns if just a carriage return is typed in response to the prompt.
// If FixedProc is supplied, then instead of calling Proc(cs, arg) it
// calls FixedProc(cs, entry, arg).
[
DefaultArgs(lv na, -2, false, 0, maxCmdChars, maxCmdPhrases, 0)
[ //repeat
let cs = InitCmd(numChars, numPhrases)
if cs ne 0 then
[
Wss(cs, prompt)
let entry = GetKeywordOrCR(cs, kt)
if entry ne 0 then
test FixedProc eq 0
ifso (entry!0)(cs, arg)
ifnot FixedProc(cs, entry, arg)
Closes(cs)
if entry eq 0 & returnOnCR break
]
] repeatuntil TelnetAborting()
]
//---------------------------------------------------------------------------
and TelnetCommandQuit(cs, nil) be
//---------------------------------------------------------------------------
// This command procedure quits out of the innermost TelnetCommandLoop
[
Closes(cs)
ReturnFrom(TelnetCommandLoop)
IFSError(ecReturnFromReturned)
]
//---------------------------------------------------------------------------
and TelnetSubcommandPrompt() =
//---------------------------------------------------------------------------
CtxRunning>>TCtx.userInfo>>UserInfo.capabilities ne 0?
bangSubPrompt, atSubPrompt;
//---------------------------------------------------------------------------
and Plural(number) = number eq 1? singularString, pluralString;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
and TelnetAborting() = CtxRunning>>TCtx.aborting ne 0
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
and SelectKeyword(cs, key1, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil; numargs na) = valof
//---------------------------------------------------------------------------
// Takes a list of up to 15 keywords, calls GetKeyword with that list,
// and returns the index (1-15) of the one matching the word typed in.
// Keyword arguments may be omitted by supplying zero in some argument
// positions; this permits keywords to be included conditionally.
[
Puts(cs, $*s)
let kt = nil
if EnableCatch(cs) then [ DestroyKeywordTable(kt); EndCatch(cs) ]
kt = CallWithArgVec(CreateKeywordIntegerMap, lv key1, na-1)
let which = GetKeyword(cs, kt)!0
DestroyKeywordTable(kt)
DisableCatch(cs)
resultis which
]
//---------------------------------------------------------------------------
and CreateKeywordIntegerMap(key1, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil; numargs na) = valof
//---------------------------------------------------------------------------
// Takes a list of up to 15 keywords and returns a keyword table
// containing those keywords, each of whose entries is the index (1-15)
// of the corresponding keyword in the argument list.
// Keyword arguments may be omitted by supplying zero in some argument
// positions; this permits keywords to be included conditionally.
[
let kt = CreateKeywordTable(na)
for i = 1 to na do
[
let keyword = (lv key1)!(i-1)
if keyword ne 0 then InsertKeyword(kt, keyword)!0 = i
]
resultis kt
]
//---------------------------------------------------------------------------
and TelnetConfirm(string; numargs na) = valof
//---------------------------------------------------------------------------
// Requests an isolated confirmation, i.e., one not in the context of
// an existing command line.
[
let result = false
let ccs = InitCmd(50, 1)
if ccs ne 0 then
[
result = Confirm(ccs, na gr 0 & string)
Closes(ccs)
]
resultis result
]