#include <system_io_constants.h>

#define CV char_varying

extern void s$error (short *status, CV(32) *caller, CV(256) *msg);

extern void s$attach_port (CV(32) *port_name, CV(256)* path,
    short *hold, short *port_id, short *status);

extern void s$open (short *port_id, short *organization,
    short *max_rec_len, short *io_type, short *locking_type,
    short *access_mode, CV(32) *index_name, short *status);

extern void s$detach_port (short *port_id, short *status);

extern void s$close (short *port_id, short *status);

extern void s$seq_read (short *port_id, short *buff_size,
    short *rec_len, void *buffer, short *status);

extern void s$seq_write (short *port_id, short *rec_length,
    void *buffer, short *status);

extern void s$parse_command (CV(32) *caller, short *status, ... );

static CV(32) caller = "ckltxt";
static CV(40) in_def = "text_file:pathname,required";
static CV(40) out_def = "binary_file:pathname.pm,required";
static CV(3)  end_def = "end";
static CV(32) in_port_name = "in_port";
static CV(32) out_port_name = "out_port";
static CV(32) index_name = "";

void cklxtr (void)
{
  short status;
  short buff_len;
  short rec_len;
  char  buff[4096];
  char  txt_buff[80];
  int   buff_ndx;
  int   txt_ndx;
  CV(256) in_path;
  CV(256) out_path;
  short   in_port;
  short   out_port;
  short   flag;
  short   io_type;
  short   lock_type;
  short   access;
  short   org;
  unsigned byte;
  int      nybble;
  int      null_cnt;

  s$parse_command (&caller, &status,
                   &in_def, &in_path,
                   &out_def, &out_path,
                   &end_def);

  if (status)
    return;

  flag = 0;
  s$attach_port (&in_port_name, &in_path, &flag, &in_port, &status);
  if (status)
  {
    s$error (&status, &caller, &in_path);
    return;
  }

  org = STREAM_FILE;
  buff_len = sizeof buff;
  io_type = INPUT_TYPE;
  lock_type = READ_LOCK;
  access = SEQUENTIAL_MODE;
  s$open (&in_port, &org, &buff_len, &io_type, &lock_type, &access,
          &index_name, &status);
  if (status)
  {
    s$error (&status, &caller, &in_path);
    return;
  }

  flag = 0;
  s$attach_port (&out_port_name, &out_path, &flag, &out_port, &status);
  if (status)
  {
    s$error (&status, &caller, &out_path);
    return;
  }

  org = FIXED_FILE;
  buff_len = sizeof buff;
  io_type = OUTPUT_TYPE;
  lock_type = WRITE_LOCK;
  access = SEQUENTIAL_MODE;
  s$open (&out_port, &org, &buff_len, &io_type, &lock_type, &access,
          &index_name, &status);
  if (status)
  {
    s$error (&status, &caller, &out_path);
    return;
  }

  buff_ndx = 0;
  while (1)
  {
    buff_len = sizeof txt_buff;
    s$seq_read (&in_port, &buff_len, &rec_len, &txt_buff, &status);
    if (status)
      break;

    if (txt_buff[0] == 'Z') /* it's a null record */
    {
      nybble = txt_buff[1] - '0';
      if (nybble > 9)
        nybble = nybble - ('9' - 'A' - 1);
      byte = nybble;
      nybble = txt_buff[2] - '0';
      if (nybble > 9)
        nybble = nybble - ('A' - '9' - 1);
      byte = ((16 * byte) + nybble);
      for (null_cnt = 0; null_cnt < byte * 32; null_cnt ++)
      {
        buff[buff_ndx] = 0;
        buff_ndx ++;
      }
    }
    else /* it is a data record */
    {
      for (txt_ndx = 0; txt_ndx < 64; txt_ndx += 2)
      {
	nybble = txt_buff[txt_ndx] - '0';
	if (nybble > 9)
	  nybble = nybble - ('9' - 'A' - 1);
	byte = nybble;
	nybble = txt_buff[txt_ndx + 1] - '0';
	if (nybble > 9)
	  nybble = nybble - ('A' - '9' - 1);
	byte = ((16 * byte) + nybble);
	buff[buff_ndx] = byte;
        buff_ndx ++;
      }
    }

    if (buff_ndx == sizeof buff) /* one block is finished */
    {
      rec_len = buff_ndx;
      buff_ndx = 0;
      s$seq_write (&out_port, &rec_len, &buff, &status);
      if (status)
      {
        s$error (&status, &caller, &out_path);

        s$close (&in_port, &status);
        s$detach_port (&in_port, &status);

        s$close (&out_port, &status);
        s$detach_port (&out_port, &status);

        return;
      } /* if status != 0 */
    } /* if buff_ndx is sizeof buff */
  } /* while (1) */

  s$close (&in_port, &status);
  s$detach_port (&in_port, &status);

  s$close (&out_port, &status);
  s$detach_port (&out_port, &status);

}
