unit judging;

interface

const
  Digits = ['0'..'9'];
  DosPrompt: char = '>';

type
  CharSet = set of char;
  Role = (Competitor, Evaluator);

var
  Show: boolean;
  SwallowEcho: boolean;
  CRrepeat: integer; { each CR sent this many times }
  LogFile: text;

procedure InitJudging(r: Role);
procedure ShowChar(c: char);
procedure SkipRemoteTo(s: CharSet; var ch: char);
procedure WriteRemote({const} s: string);
procedure AbortRemote;
procedure WriteRemoteCR;
procedure ReadRemoteCR;
procedure ReadRemote(var s: string);
function ReadRemoteInt: integer;

implementation

const
  ETX = chr(3);
  LF = chr(10);
  CR = chr(13);

type
  States = (Send, Receive);

var
  Who: Role;
  RemoteInp, RemoteOut: file of char;
  State: States;
  LookAheadChar: char;
  Ahead: boolean;

procedure InitJudging(r: Role);
  var ior: integer;
  begin
  Who := r ;
  case Who of
    Competitor: begin
      Assign(LogFile, 'LogFileC.bak') ;
      {$I-}Erase(LogFile){$I+} ; ior := IOResult ;
      Assign(LogFile, 'LogFileC.txt') ;
      {$I-}Rename(LogFile, 'LogFileC.bak'){$I+} ; ior := IOResult ;
      Assign(LogFile, 'LogFileC.txt') ;
      Rewrite(LogFile)
      end { Competitor } ;
    Evaluator: begin
      Assign(RemoteInp, 'COM2') ; reset(RemoteInp) ;
      Assign(RemoteOut, 'COM2') ; rewrite(RemoteOut) ;
      State := Receive ; Ahead := false ;
      Assign(LogFile, 'LogFileE.bak') ;
      {$I-}Erase(LogFile){$I+} ; ior := IOResult ;
      Assign(LogFile, 'LogFileE.txt') ;
      {$I-}Rename(LogFile, 'LogFileE.bak'){$I+} ; ior := IOResult ;
      Assign(LogFile, 'LogFileE.txt') ;
      Rewrite(LogFile)
      end { Evaluator }
    end { case }
  end { InitJudging } ;

procedure ShowChar(c: char);
  begin
  if c < ' ' then write('^', chr(ord('@')+ord(c)))
  else if c = '^' then write('^!')
  else if c > '~' then write('^', ord(c))
  else write(c)
  end { ShowChar } ;

procedure Switch(s: States);
  begin
  if s <> State then begin
    if Show then begin
      writeln ;
      case s of
        Send: write('>') ;
        Receive: write('<') ;
        end { case }
      end { if } ;
    State := s
    end { if }
  end { Switch } ;

procedure GetRemoteChar(var ch: char);
  begin
  if Ahead then begin
    ch := LookAheadChar ;
    Ahead := false
    end { then }
  else read(RemoteInp, ch) ;
  if Show then ShowChar(ch)
  end { GetRemoteChar } ;

procedure UnGetRemoteChar(ch: char);
  begin
  if Ahead then writeln('Error: UnGetRemoteChar') ;
  LookAheadChar := ch ;
  Ahead := true
  end { GetRemoteChar } ;

procedure SkipRemoteTo(s: CharSet; var ch: char);
  begin
  Switch(Receive) ;
  repeat GetRemoteChar(ch) until ch in s ;
  end { SkipTo } ;

procedure WriteRemote({const} s: string);
  var i: integer; ch: char;
  begin
  Switch(Send) ;
  for i := 1 to Length(s) do begin
    write(RemoteOut, s[i]) ; { s[i] give compile error when using const s }
    if SwallowEcho then GetRemoteChar(ch)
    end { for i }
  end { WriteRemote } ;

procedure AbortRemote;
  var ch: char;
  begin
  Switch(Send) ;
  ch := ETX ;
  write(RemoteOut, ch) ;
  repeat GetRemoteChar(ch) until ch = DosPrompt
  end { AbortRemote } ;

procedure WriteRemoteCR;
  var ch: char; i: integer;
  begin
  Switch(Send) ;
  ch := CR ;
  for i := 1 to CRrepeat do write(RemoteOut, ch) ;
  if SwallowEcho then begin
    repeat GetRemoteChar(ch) until ch = LF
    end { if } ;
  end { WriteRemoteCR } ;

procedure ReadRemoteCR;
  var ch: char;
  begin
  Switch(Receive) ;
  repeat GetRemoteChar(ch) until ch = LF
  end { ReadRemoteCR } ;

procedure ReadRemote(var s: string);
  var ch: char;
  begin
  Switch(Receive) ;
  s := '' ;
  repeat
    GetRemoteChar(ch) ;
    if ch in [CR, LF] then UnGetRemoteChar(ch)
    else s := s+ch
    until ch in [CR, LF]
  end { ReadRemote } ;

function ReadRemoteInt: integer;
  var i: integer; ch: char;
  begin
  Switch(Receive) ;
  i := 0 ;
  repeat GetRemoteChar(ch) until ch in Digits ;
  while ch in Digits do begin
    i := 10 * i + ord(ch) - ord('0') ;
    GetRemoteChar(ch)
    end { while } ;
  UnGetRemoteChar(ch) ;
  ReadRemoteInt := i
  end { ReadRemoteInt } ;

begin
Who := Competitor ;
Show := true ; SwallowEcho := true ;
CRrepeat := 1
end.