// IfsScavCSDsp.bcpl -- Ifs Scavenger dependent portion of the
//	command scanner package.  This file started out life as
//	CmdScanDisplay.bcpl
// Copyright Xerox Corporation 1979, 1980
// Last modified November 16, 1980  3:11 PM 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; Noop
CurrentPhrase; BackupPhrase; Dismiss
FilePos; SetFilePos; DoubleIncrement
]


//---------------------------------------------------------------------------
let DefErase(cs, first, last, context) be
//---------------------------------------------------------------------------
[
//scavenger's dsp is a split stream:
let ds = cs>>CS.dspS>>ST.par1  //par1 -> display stream
let ks = cs>>CS.dspS>>ST.par2  //par2 -> disk stream
let bits = 0
let chars = 0
for i = first to last do
   [
   let char = cs>>CS.buf>>Buf↑i
   if char ls #200 then
      [
      if char eq $*n then bits = 9999
      chars = chars +1
      bits = bits + (char ge #40? CharWidth(ds, char),
       CharWidth(ds, $↑)+CharWidth(ds, char+#100))
      ]
   ]
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 #200 then Puts(ds, cs>>CS.buf>>Buf↑i)
      ]
unless ks>>ST.puts eq Noop do
   [
   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>>ST.par1)
Dismiss(50)
InvertWindow(cs>>CS.dspS>>ST.par1)
Resets(cs>>CS.keyS)
]


//---------------------------------------------------------------------------
and InvertWindow(ds) be
//---------------------------------------------------------------------------
[
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
]