// FtpCliUtil.bcpl
// Copyright Xerox Corporation 1979, 1980
// Last modified October 8, 1980  4:57 PM by Boggs

get "FtpProt.decl"
get "FtpUser.decl"

external
[
// outgoing procedures
CliGetString; CliConfirm; CliError
CliSwitches; BadSwitch; IsCommand

// incoming procedrues
Allocate; FreePointer; MoveBlock; CliQuit
Gets; Endofs; Puts; Closes; Resets
InitCmd; Confirm; Wss; PutTemplate

// incoming statics
sysZone; userDsp; userKeys; errorFlag

// outgoing statics
overwrite; selective; verify
all; dates; update; query
cliStream; cli
]

structure String [ length byte; char↑1,1 byte ]

static
[
overwrite; selective; verify
all; dates; update; query
cliStream; cli
]

//----------------------------------------------------------------------------
let CliGetString(quitOnNoChars; numargs na) = valof
//----------------------------------------------------------------------------
// Returns 0 or a string allocated from sysZone.
// The number of switches read is in
//  string>>String.char↑(string>>String.length+1).
// That many switches follow.
[
if na eq 0 then quitOnNoChars = true
let quotePending, count, char = false, 0, nil
let string = vec 128
   [
   if Endofs(cliStream) test count eq 0
      ifnot break
      ifso test quitOnNoChars
         ifso CliQuit()
         ifnot resultis 0
   char = Gets(cliStream)
   if char eq $*S % char eq $*N test count eq 0 ifso loop ifnot break
   if char eq QuoteChar then [ quotePending = true; loop ]
   if char eq $/ unless quotePending break
   if count le 255 then count = count+1
   string>>String.char↑count = char
   quotePending = false
   ] repeat
string>>String.length = count
count = count+1
if char eq $/ then
   [
   if Endofs(cliStream) break
   char = Gets(cliStream)
   if char eq $*S % char eq $*N break
   if char eq $/ loop
   if count le 257 then count = count+1
   string>>String.char↑count = char
   ] repeat
string>>String.char↑(string>>String.length+1) =
 count - string>>String.length -1
let res = Allocate(sysZone, count rshift 1 +1)
MoveBlock(res, string, count rshift 1 +1)
resultis res
]

//---------------------------------------------------------------------------
and CliSwitches() be
//---------------------------------------------------------------------------
[
let notFlag = false
for i = 1 to cli>>String.char↑(cli>>String.length+1) do
   [
   switchon cli>>String.char↑(cli>>String.length+1+i) into
      [
      case $S: case $s: [ selective = not notFlag; endcase ]
      case $O: case $o: [ overwrite = not notFlag; endcase ]
      case $V: case $v: [ verify = not notFlag; endcase ]
      case $Q: case $q: [ query = not notFlag; endcase ]
      case $N: case $n: [ overwrite = notFlag; endcase ]
      case $D: case $d: [ dates = not notFlag; endcase ]
      case $A: case $a: [ all = not notFlag; endcase ]
      case $U: case $u: docase $>
      case $C: case $c: endcase
      case $#: [ update = update % (notFlag? dEQ, dNE); endcase ]
      case $>: [ update = update % (notFlag? dLE, dGR); endcase ]
      case $<: [ update = update % (notFlag? dGE, dLS); endcase ]
      case $=: [ update = update % (notFlag? dNE, dEQ); endcase ]
      case $-: [ notFlag = not notFlag; loop ]
      default: [ BadSwitch(i); endcase ]
      ]
   notFlag = false
   ]
if update then dates = true
FreePointer(lv cli)
]

//---------------------------------------------------------------------------
and BadSwitch(i) be
//---------------------------------------------------------------------------
   CliError("*NUnrecognized switch /$C", false,
    cli>>String.char↑(cli>>String.length+1+i))

//---------------------------------------------------------------------------
and IsCommand() = cli>>String.char↑(cli>>String.length+1) ne 0 % cli eq 0
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
and CliConfirm(string; numargs na) = valof
//---------------------------------------------------------------------------
[
if na eq 0 then string = 0
let cs = InitCmd(256, 2, 0, 0, 0, userKeys, userDsp)
if cs eq 0 resultis false
let ok = Confirm(cs, string)
Closes(cs)
resultis ok
]

//---------------------------------------------------------------------------
and CliError(string, fatal, arg1, arg2, arg3; numargs na) = valof
//---------------------------------------------------------------------------
[
if na ls 2 then fatal = false
Puts(userDsp, $*007)
if na ge 1 then PutTemplate(userDsp, string, arg1, arg2, arg3)
test fatal 
   ifnot
      [
      unless errorFlag resultis false
      Resets(userKeys)
      if CliConfirm("*NDo you want to continue? ") resultis false
      ]
   ifso
      [
      Resets(userKeys)
      Wss(userDsp, "*NType any character to finish")
      Gets(userKeys)
      ]
abort
]