$SEARCH 'KRMWNDW', '*IO.', '*INTERFACE.'$
{

This file, KRMRPT.TEXT, contains the error and status reporting
modules used by all other Kermit modules.  The following modules
reside in this file:

	ERR_CODES	Error code definitions
	KRMRPT		Error and status reporting procedures
}


{

Module ERR_CODES defines the integer error code values that can be
returned by a procedure to indicate whether it completed successfully,
or, if not, what error occurred.  Function ERRSTR returns the error
message string associated with the error.

All Kermit modules have access to ERR_CODES.

}
module err_codes;
export

const
  error_string_length = 80;       { Maximum length of error strings }

{ Facility code definitions.  These codes identify the facility generating
  the error.
}

cmdfac = 1*128;             { command interpreter }
trmfac = 2*128;             { terminal emulation code }
iofac  = 3*128;             { io error }
krmfac = 4*128;             { kermit protocol machine }

{  Status code definitions.  Successful return codes are odd, those
   corresponding to error conditions are even.  Returned by functions,
   etc.
}
  
  success       = 1;
  
  
{  Error condition status codes }
{  Codes returned by lookup_key }
  
  ambig_keyword = 2 + cmdfac;
  no_keyword    = 4 + cmdfac;

{  Codes returned by parse  }

  not_confirmed = 6 + cmdfac;
  integer_error = 8 + cmdfac;
  no_match      = 10 + cmdfac;
  non_digit     = 12 + cmdfac;        { Non-digit character encountered }
  integer_overflow = 14 + cmdfac;     { Integer overflow }
  null_string   = 16 + cmdfac;        { null string given as argument }
  parse_after_eol = 18 + cmdfac;      { parse called after eol parsed }
  
{  Codes returned by read_break }
  
  back_past_field = 20 + cmdfac;
  abort_line    = 22 + cmdfac;
  

type
   error_string = string[ error_string_length ];


function errstr ( errcode : integer ) : error_string;
  
$page$
implement

function errstr ( errcode : integer ) : error_string;
{

Returns the error string associated with each error.
}
  var s : error_string;
  begin
  case errcode of
    success:            s := 'Success';
    
  { Codes returned by lookup_key }
  
    ambig_keyword:      s := 'Ambiguous keyword';
    no_keyword:         s := 'No keywords match this input';
  
  {  Codes returned by parse  }
  
    not_confirmed:      s := 'Not confirmed';
    integer_error:      s := 'Error reading integer';
    no_match:           s := 'No defined keywords match this input';
    non_digit:          s := 'Non-digit character encountered';
    integer_overflow:   s := 'Integer overflow';
    null_string:        s := 'Null string given as argument';
    parse_after_eol:    s := 'Parse called after end of line parsed';
    
  {  Codes returned by read_break }
    
    back_past_field:    s := 'Input deleted past beginning of field';
    abort_line:         s := 'Line aborted by CTRL-U';
   end;  { case }
  errstr := s;
  end;  { function errstr }

end;  { module err_codes }


$PAGE$
{

Module KRMRPT handles error and status reporting for the rest of
Kermit.  Basically, except for command echoing, anything that is
displayed on the screen is put there by procedures in this module.
These procedures do the proper text formatting, positioning, etc., and
then call procedures in module WINDOWLIB (in file KRMWNDW.TEXT) to
actually do the screen output.

All other Kermit modules have access to KRMRPT.

}
module  krmrpt;
import  windowlib,
        err_codes;

export

var
  help_window, command_window, error_window, stat_window : window_ptr;
  
type

  { Packet transfer statistics record }

  kermit_statistics = record
         NumSendPacks : integer;   { number of packets sent }
         NumRecvPacks : integer;   { number of packets received }
         NumACKsent : integer;     { number of ACKs we've sent }
         NumNAKsent : integer;     { number of NAKs we've sent }
         NumACKrecv : integer;     { number of ACKs we've received }
         NumNAKrecv : integer;     { number of NAKs we've received }
         NumBADrecv : integer;     { number of non-ACKs we've received when }
                                   { waiting for an ACK }
         RunTime: integer;         { elapsed time for current transaction }
         ChInFile : integer;       { number of characters in file }
         ChInPack : integer;       { number of characters in packets }
         packet_overhead : integer; { percent overhead of packetizing }
         effrate : integer;        { effective baud rate of transfer }
         end;  { record }

  KermitStates = (FileData,RecvInit,SendInit,Break,
                  FileHeader,EOFile,Complete,Abort);
  
  Transfer_type = (Transmit, Receive, Invalid);
  

procedure set_logfile( var fnm : string );
procedure get_logfile( var fnm : string );
procedure report_status( var report : string );
procedure report_log( var report : string );
procedure report_error( code : integer; var where_msg : string );
procedure init_cmd_windows;
procedure clear_status_window;
procedure init_packet_display( runtype : transfer_type );
procedure report_send_packet( seq : integer );
procedure report_receive_file( var fnm : string );
procedure report_send_file( var fnm : string );
procedure report_packet_statistics( stats : kermit_statistics;
                                    runtype : transfer_type );
function check_error( code : integer; var where_msg : string ) : boolean;

implement

const
  send_packet_y = 2;
  packet_stat_x = 25;
  packet_stat_y = 4;
  stat_random_x = 0;
  stat_random_y = 14;
  file_report_x = 0;
  file_report_y = 0;
  
var
  log_filename : string[50];
  log_file : text;
  log_on : boolean;
  send_packet_x : integer;            { window coords of send packet # }
  report : string[80];
  rpos : integer;
  
procedure set_logfile( var fnm : string );
  begin
  if strlen(fnm) = 0
     then begin
       log_on := false;
       log_filename := 'OFF';
       end
     else begin
          log_on := true;
          log_filename := fnm;
          rewrite(log_file,log_filename);
          end;
  end;  { procedure set_logfile }
  
procedure get_logfile( var fnm : string );
  begin
  fnm := log_filename;
  end;  { procedure get_logfile }
  
procedure report_status( var report : string );
  begin
  writeln_window_string( stat_window, report );
  end;  { procedure report_status }

procedure report_log( var report : string );
  begin
  if log_on
    then writeln(log_file, report);
  end;  { procedure report_status }

procedure report_error( code : integer; var where_msg : string );
  var report : string [80];
      rpos : integer;
  begin
  setstrlen(report,0);
  strwrite(report,1,rpos,'?Error ',where_msg, ' - ', errstr(code));
  clear_window(error_window);
  writeln_window_string( error_window, report );
  end;  { procedure report_error }

$page$
procedure init_cmd_windows;
  begin
  stat_window    := init_window(0,screen_x_max, 0,16);
  help_window    := init_window(0,screen_x_max, 17,20);
  command_window := init_window(0,screen_x_max, 21,21);
  error_window   := init_window(0,screen_x_max, 22,23);
  end;  { procedure init_cmd_windows }
  
procedure clear_status_window;
  begin
  clear_window(stat_window);
  end;  { procedure clear_status_window }
  
procedure init_packet_display( runtype : transfer_type );
  var lab : string[80];
  begin
  clear_window(stat_window);
  lab := 'Sending Packet # ';
  send_packet_x := strlen(lab);
  gotoxy_window(stat_window, 0, send_packet_y);
  writeln_window_string( stat_window, lab);
  clear_eol_window(stat_window);
  
  gotoxy_window( stat_window, 0, packet_stat_y );
  setstrlen(report,0);
  strwrite(report,1,rpos,'Packets sent');
  report_status(report);
  setstrlen(report,0);
  strwrite(report,1,rpos,'Packets received');
  report_status(report);
  setstrlen(report,0);
  if runtype = transmit
     then strwrite(report,1,rpos,'Total chars. sent')
     else strwrite(report,1,rpos,'Total chars. rcvd');
  report_status(report);
  setstrlen(report,0);
  if runtype = transmit
     then strwrite(report,1,rpos,'Data chars. sent')
     else strwrite(report,1,rpos,'Data chars. rcvd');
  report_status(report);
  
  setstrlen(report,0);
  strwrite(report,1,rpos,'Overhead (%)');
  report_status(report);
  setstrlen(report,0);
  strwrite(report,1,rpos,'Effective Rate');
  report_status(report);
  setstrlen(report,0);
  strwrite(report,1,rpos,'Number of ACK');
  report_status(report);
  setstrlen(report,0);
  strwrite(report,1,rpos,'Number of NAK');
  report_status(report);
  IF (RunType = Transmit)
    THEN BEGIN
      setstrlen(report,0);
      strwrite(report,1,rpos,'Number of BAD');
      report_status(report);
      END;
  gotoxy_window(stat_window, stat_random_x, stat_random_y);
  end;  { procedure init_packet_display }
  
procedure report_send_packet( seq : integer );
  begin
  gotoxy_window(stat_window, send_packet_x, send_packet_y);
  setstrlen(report,0);
  strwrite(report,1,rpos,seq:1);
  write_window_string(stat_window, report);
  clear_eol_window(stat_window);
  gotoxy_window(stat_window, stat_random_x, stat_random_y);
  end;  { report_send_packet }
  
procedure report_send_file( var fnm : string );
  begin
  gotoxy_window(stat_window, file_report_x, file_report_y);
  setstrlen(report,0);
  strwrite(report,1,rpos,'Sending file   ',fnm);
  write_window_string(stat_window, report);
  clear_eol_window(stat_window);
  gotoxy_window(stat_window, stat_random_x, stat_random_y);
  end;  { procedure report_send_file }

procedure report_receive_file( var fnm : string );
  begin
  gotoxy_window(stat_window, file_report_x, file_report_y);
  setstrlen(report,0);
  strwrite(report,1,rpos,'Receiving file ',fnm);
  write_window_string(stat_window, report);
  clear_eol_window(stat_window);
  gotoxy_window(stat_window, stat_random_x, stat_random_y);
  end;  { procedure report_receive_file }

procedure report_packet_statistics( stats : kermit_statistics;
                                    runtype : transfer_type );
  var row : integer;
  procedure report_num( i : integer );
    begin
    setstrlen(report,0);
    strwrite(report,1,rpos,i:5);
    gotoxy_window(stat_window, packet_stat_x, row);
    write_window_string(stat_window,report);
    row := row + 1;
    end;  { procedure report_num }
    
  begin
  row := packet_stat_y;
  report_num(stats.NumSendPacks);
  report_num(stats.NumRecvPacks);
  report_num(stats.ChInPack);
  report_num(stats.ChInFile);
  report_num(stats.packet_overhead);
  report_num(stats.effrate);
  IF (RunType = Transmit)
    THEN BEGIN  { for transmit }
      report_num(stats.NumACKrecv);
      report_num(stats.NumNAKrecv);
      report_num(stats.NumBADrecv);
      END  { for transmit }
    ELSE BEGIN   { for Receive }
      report_num(stats.NumACKsent);
      report_num(stats.NumNAKsent);
      END;  { for Receive }
    gotoxy_window(stat_window, stat_random_x, stat_random_y);
  end;  { procedure report_packet_statistics }


$page$
{ check_error           Checks given condition code.  Returns false if code
  is successful.  If code is error code, prints associated error message
  and returns true.
}
function check_error( code : integer; var where_msg : string ) : boolean;
  var ret : boolean;
  begin
    ret := false;
    if not odd(code)       { successful conditions are odd, failing (error)
                          conditions are even }
       then begin
       report_error( code, where_msg );
       ret := true;
       end;
    check_error := ret;
  end;  { procedure check_error }
     
end.  { module krmrpt }
