// CmdScanDisplay.bcpl -- Alto display dependent portion of
//			command scanner package
// ***** MODIFIED FOR FTP *****
// Copyright Xerox Corporation 1979
// Last modified June 3, 1978  1:43 AM by Boggs

get "CmdScan.decl"
get "AltoDefs.d"

external
[
// outgoing procedures
DefErase; DefError; DefBreak; DefEcho; CmdError; InvertWindow

// incoming procedures
CharWidth; GetBitPos; GetLmarg; EraseBits
Puts; Resets; Wss; SysErr
CurrentPhrase; BackupPhrase; Dismiss
FilePos; SetFilePos; DoubleIncrement
]


//---------------------------------------------------------------------------
let DefErase(cs, first, last, context) be
//---------------------------------------------------------------------------
[
let ds = cs>>CS.dspS
let ks = 0
//if this is a split stream (type = 12345) then
//	par1 is the display stream
//	par2 is the file stream
if ds>>ST.type eq 12345 then
   [
   ks = ds>>ST.par2
   ds = ds>>ST.par1
   ]
let bits = 0
let chars = 0
for i = first to last do
   [
   let char = cs>>CS.buf>>Buf↑i
   if char ls 200b then
      [
      if char eq $*n then bits = 9999
      chars = chars +1
      bits = bits + (char ge 40b? CharWidth(ds, char),
       CharWidth(ds, $↑)+CharWidth(ds, char+100b))
      ]
   ]
test bits le GetBitPos(ds)-GetLmarg(ds)
   ifso EraseBits(ds, -bits)
   ifnot
      [  //erasing past left margin
      Resets(ds)
      for i = 0 to first-1 do
         if cs>>CS.buf>>Buf↑i ls 200b then Puts(ds, cs>>CS.buf>>Buf↑i)
      ]
if ks ne 0 then
   [
   let filePos = vec 1; FilePos(ks,filePos)
   DoubleIncrement(filePos,-chars)
   SetFilePos(ks,filePos)
   ]
]

//---------------------------------------------------------------------------
and DefBreak(cs, char) = char eq $*n % char eq $*s % char eq $*033
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
and DefEcho(cs, char) = not CurrentPhrase(cs)>>PD.PhraseTerminator(cs, char)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
and DefError(cs, ec) be
//---------------------------------------------------------------------------
[
cs>>CS.errorCode = ec
switchon ec into
   [
   case ecCmdDelete:
      Wss(cs>>CS.dspS, " XXX")  //fall into next case
   case ecCmdDestroy:
      [ cs>>CS.destroy = true; BackupPhrase(cs, cs>>CS.iPhOut) ]
   case ecCmdTooLong:  //just blink window and do nothing
      [ CmdError(cs); endcase ]
   case ecKeyAmbiguous:
   case ecBackupAppend:
      [ CmdError(cs); BackupPhrase(cs, 0, editAppend) ]
   case ecTooManyPhrases:
   case ecEndOfPhrase:
      SysErr(cs, ec)
   default:  //all types of syntax errors get same handling
      CmdError(cs, " ?")  //fall into next case
   case ecBackupReplace:
      BackupPhrase(cs)
   ]
]


//---------------------------------------------------------------------------
and CmdError(cs, string; numargs na) be
//---------------------------------------------------------------------------
//Displays string if present, blinks display window, and resets keyboard
[
if na gr 1 & string ne 0 then Wss(cs, string)
InvertWindow(cs>>CS.dspS)
Dismiss(50)
InvertWindow(cs>>CS.dspS)
Resets(cs>>CS.keyS)
]


//---------------------------------------------------------------------------
and InvertWindow(ds) be
//---------------------------------------------------------------------------
[
unless ds>>ST.type eq stTypeDisplay return
let dcb = ds>>DS.fdcb
   [
   dcb>>DCB.background = not dcb>>DCB.background
   if dcb eq ds>>DS.ldcb then break
   dcb = dcb>>DCB.next
   ] repeat
]